Skip to content

Commit 9ab7d33

Browse files
authored
Merge pull request #90 from viktoraseev/wse-quotes-importer
Warsaw Stock Exchange quotes importer
2 parents 27a5052 + e9b33b4 commit 9ab7d33

File tree

4 files changed

+49
-3
lines changed

4 files changed

+49
-3
lines changed

jal/constants.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ class MarketDataFeed(PredefinedList, QObject):
233233
SMA_VICTORIA = 7
234234
COIN = 8
235235
MILAN = 9 # Borsa Italiana, Milan Stock Exchange
236+
WSE = 10 # Warsaw Stock Exchange (WSE)
236237

237238
def __init__(self):
238239
super().__init__()
@@ -247,7 +248,8 @@ def __init__(self):
247248
self.FRA: self.tr("Frankfurt Borse"),
248249
self.SMA_VICTORIA: self.tr("Victoria Seguros"),
249250
self.COIN: self.tr("Coinbase"),
250-
self.MILAN: self.tr("Borsa Italiana")
251+
self.MILAN: self.tr("Borsa Italiana"),
252+
self.WSE: self.tr("Warsaw Stock Exchange")
251253
}
252254

253255

jal/data_import/statement.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ class Statement(QObject): # derived from QObject to have proper string transla
121121
'MOEX': MarketDataFeed.RU,
122122
'COIN': MarketDataFeed.COIN,
123123
'BVME': MarketDataFeed.MILAN,
124-
'BVME.ETF': MarketDataFeed.MILAN
124+
'BVME.ETF': MarketDataFeed.MILAN,
125+
'WSE': MarketDataFeed.WSE
125126
}
126127

127128
def __init__(self):

jal/net/downloader.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ def download_asset_prices(self, start_timestamp, end_timestamp, sources_list):
165165
MarketDataFeed.FRA: self.YahooFRA_Downloader,
166166
MarketDataFeed.SMA_VICTORIA: self.Victoria_Downloader,
167167
MarketDataFeed.COIN: self.Coinbase_Downloader,
168-
MarketDataFeed.MILAN: self.EuronextMilan_DataReader
168+
MarketDataFeed.MILAN: self.EuronextMilan_DataReader,
169+
MarketDataFeed.WSE: self.Stooq_DataReader
169170
}
170171
assets = JalAsset.get_active_assets(start_timestamp, end_timestamp)
171172
assets = [(x['asset'], x['currency']) for x in assets if x['asset'].quote_source(x['currency']) in sources_list]
@@ -523,6 +524,38 @@ def visitor_body(text, cm, tm, font_dict, font_size):
523524
self._victoria_quotes.append({'name': fund_name, 'price': Decimal(price.replace(',', '.'))})
524525
return self._victoria_quotes
525526

527+
def Stooq_DataReader(self, asset, currency_id, start_timestamp, end_timestamp):
528+
"""Fetches historical data from Warsaw Stock Exchange (GPW) using Stooq API"""
529+
url = "https://stooq.com/q/d/l/"
530+
params = {
531+
's': asset.symbol(currency_id),
532+
'd1': datetime.fromtimestamp(start_timestamp, tz=timezone.utc).strftime('%Y%m%d'),
533+
'd2': datetime.fromtimestamp(end_timestamp, tz=timezone.utc).strftime('%Y%m%d'),
534+
'i': 'd'
535+
}
536+
537+
self._request = WebRequest(WebRequest.GET, url, params=params)
538+
self._wait_for_event()
539+
540+
try:
541+
data = pd.read_csv(
542+
StringIO(self._request.data()),
543+
converters={'Close': lambda x: Decimal(x.strip())} # не теряем точность при чтении
544+
)
545+
if data.empty:
546+
return None
547+
548+
# Convert dates and filter required columns
549+
data['Date'] = pd.to_datetime(data['Date'], format='%Y-%m-%d', utc=True)
550+
551+
close = data[['Date', 'Close']].set_index('Date')
552+
close.sort_index(inplace=True)
553+
return close
554+
555+
except (ParserError, KeyError, ValueError) as e:
556+
logging.error(f"Failed to parse Stooq data: {str(e)}")
557+
return None
558+
526559
def Coinbase_Downloader(self, asset, currency_id, start_timestamp, end_timestamp):
527560
currency_symbol = JalAsset(currency_id).symbol()
528561
url = f"https://api.coinbase.com/v2/prices/{asset.symbol(currency_id)}-{currency_symbol}/spot"

tests/test_downloaders.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,3 +286,13 @@ def test_Coinbase_downloader(prepare_db):
286286
downloader = QuoteDownloader()
287287
quotes_downloaded = downloader.Coinbase_Downloader(JalAsset(4), 3, d2t(230412), d2t(230414))
288288
assert_frame_equal(quotes, quotes_downloaded)
289+
290+
def test_Stooq_downloader(prepare_db):
291+
create_stocks([('CDR', '')], currency_id=3) # ID = 4
292+
downloader = QuoteDownloader()
293+
expected = pd.DataFrame({
294+
'Date': [d2dt(200102)],
295+
'Close': [Decimal('271.81')]
296+
}).set_index('Date')
297+
result = downloader.Stooq_DataReader(JalAsset(4), 3, d2t(200102), d2t(200102))
298+
assert_frame_equal(expected, result)

0 commit comments

Comments
 (0)