Skip to content

Commit 91f4839

Browse files
committed
Fix market data source usage on close position
1 parent 3753fc1 commit 91f4839

File tree

4 files changed

+116
-27
lines changed

4 files changed

+116
-27
lines changed

investing_algorithm_framework/app/algorithm.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -421,11 +421,8 @@ def get_position_percentage_of_portfolio(
421421
)
422422
full_symbol = f"{position.symbol.upper()}/" \
423423
f"{portfolio.trading_symbol.upper()}"
424-
ticker = self.get_ticker_market_data_source(portfolio.market, full_symbol)\
425-
.get_data(
426-
backtest_index_date=self.config
427-
.get(BACKTESTING_INDEX_DATETIME)
428-
)
424+
ticker = self._market_data_source_service\
425+
.get_ticker(market=portfolio.market, symbol=full_symbol)
429426
total = self.get_unallocated() + self.get_allocated()
430427
return (position.amount * ticker["bid"] / total) * 100
431428

@@ -550,8 +547,8 @@ def get_allocated(self, market=None, identifier=None) -> float:
550547

551548
symbol = f"{position.symbol.upper()}/" \
552549
f"{portfolio.trading_symbol.upper()}"
553-
ticker = self.get_ticker_market_data_source(
554-
portfolio.market, symbol
550+
ticker = self._market_data_source_service.get_ticker(
551+
symbol=symbol, market=portfolio.market,
555552
).get_data(
556553
backtest_index_date=self.config
557554
.get(BACKTESTING_INDEX_DATETIME)

investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@
88

99

1010
class MarketDataSourceService:
11+
"""
12+
This class is responsible for managing the market data sources.
13+
14+
It is used by the algorithm to get market data from different sources.
15+
The MarketDataSourceService will first check if there is a market data
16+
source that matches the symbol, market and time frame provided by the user.
17+
If there is, it will use that market data source to get the data. If there
18+
is not, it will use the MarketService to get the data.
19+
"""
1120
_market_data_sources: List[MarketDataSource] = []
1221

1322
def __init__(
@@ -25,7 +34,7 @@ def __init__(
2534
self._market_credential_service: MarketCredentialService = \
2635
market_credential_service
2736

28-
def get_ticker(self, symbol, market):
37+
def get_ticker(self, symbol, market=None):
2938
ticker_market_data_source = self.get_ticker_market_data_source(
3039
symbol=symbol, market=market
3140
)
@@ -37,7 +46,7 @@ def get_ticker(self, symbol, market):
3746

3847
return self._market_service.get_ticker(symbol, market)
3948

40-
def get_order_book(self, symbol, market):
49+
def get_order_book(self, symbol, market=None):
4150
order_book_market_data_source = self.get_order_book_market_data_source(
4251
symbol=symbol, market=market
4352
)
@@ -50,7 +59,12 @@ def get_order_book(self, symbol, market):
5059
return self._market_service.get_order_book(symbol, market)
5160

5261
def get_ohlcv(
53-
self, symbol, time_frame, from_timestamp, market, to_timestamp=None
62+
self,
63+
symbol,
64+
time_frame,
65+
from_timestamp,
66+
market=None,
67+
to_timestamp=None
5468
):
5569
ohlcv_market_data_source = self.get_ohlcv_market_data_source(
5670
symbol=symbol, market=market, time_frame=time_frame
@@ -79,40 +93,60 @@ def get_data(self, identifier):
7993
market_credential_service=self._market_credential_service
8094
)
8195

82-
def get_ticker_market_data_source(self, symbol, market):
96+
def get_ticker_market_data_source(self, symbol, market=None):
8397

8498
if self.market_data_sources is not None:
8599
for market_data_source in self._market_data_sources:
86100
if isinstance(market_data_source, TickerMarketDataSource):
87-
if market_data_source.market.lower() == market.lower() \
88-
and market_data_source.symbol.lower() \
89-
== symbol.lower():
90-
return market_data_source
101+
102+
if market is not None:
103+
if market_data_source.market.lower() == market.lower()\
104+
and market_data_source.symbol.lower() \
105+
== symbol.lower():
106+
return market_data_source
107+
else:
108+
if market_data_source.symbol.lower() \
109+
== symbol.lower():
110+
return market_data_source
91111

92112
return None
93113

94-
def get_ohlcv_market_data_source(self, symbol, market, time_frame):
114+
def get_ohlcv_market_data_source(self, symbol, time_frame, market=None):
95115

96116
if self.market_data_sources is not None:
97117
for market_data_source in self._market_data_sources:
98118
if isinstance(market_data_source, OHLCVMarketDataSource):
99-
if market_data_source.market.lower() == market.lower() \
100-
and market_data_source.symbol.lower() \
101-
== symbol.lower() and \
102-
market_data_source.timeframe == time_frame:
103-
return market_data_source
119+
120+
if market is not None:
121+
122+
if market_data_source.market.lower() == market.lower()\
123+
and market_data_source.symbol.lower() \
124+
== symbol.lower() and \
125+
market_data_source.timeframe == time_frame:
126+
return market_data_source
127+
else:
128+
if market_data_source.symbol.lower() \
129+
== symbol.lower() and \
130+
market_data_source.timeframe == time_frame:
131+
return market_data_source
104132

105133
return None
106134

107-
def get_order_book_market_data_source(self, symbol, market):
135+
def get_order_book_market_data_source(self, symbol, market=None):
108136

109137
if self.market_data_sources is not None:
110138
for market_data_source in self._market_data_sources:
111139
if isinstance(market_data_source, OrderBookMarketDataSource):
112-
if market_data_source.market.lower() == market.lower() \
113-
and market_data_source.symbol.lower() \
114-
== symbol.lower():
115-
return market_data_source
140+
141+
if market is not None:
142+
if market_data_source.market.lower() == market.lower()\
143+
and market_data_source.symbol.lower() \
144+
== symbol.lower():
145+
return market_data_source
146+
else:
147+
if market_data_source.symbol.lower() \
148+
== symbol.lower():
149+
return market_data_source
116150

117151
return None
118152

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import os
2+
3+
from investing_algorithm_framework import create_app, RESOURCE_DIRECTORY, \
4+
PortfolioConfiguration, CSVTickerMarketDataSource
5+
from tests.resources import TestBase, MarketServiceStub
6+
7+
8+
class TestMarketDataSourceService(TestBase):
9+
10+
def setUp(self) -> None:
11+
self.resource_dir = os.path.abspath(
12+
os.path.join(
13+
os.path.join(
14+
os.path.join(
15+
os.path.realpath(__file__),
16+
os.pardir
17+
),
18+
os.pardir
19+
),
20+
"resources"
21+
)
22+
)
23+
self.app = create_app(config={RESOURCE_DIRECTORY: self.resource_dir})
24+
self.app.add_portfolio_configuration(
25+
PortfolioConfiguration(
26+
market="binance",
27+
trading_symbol="USDT"
28+
)
29+
)
30+
self.app.container.market_service.override(
31+
MarketServiceStub(self.app.container.market_credential_service())
32+
)
33+
self.app.add_market_data_source(CSVTickerMarketDataSource(
34+
identifier="BTC/EUR-ticker",
35+
market="BITVAVO",
36+
symbol="BTC/EUR",
37+
csv_file_path=os.path.join(
38+
self.resource_dir,
39+
"market_data_sources",
40+
"TICKER_BTC-EUR_BITVAVO_2021-06-02:00:00_2021-06-26:00:00.csv"
41+
)
42+
))
43+
self.app.initialize()
44+
45+
def test_create_limit_order(self):
46+
market_data_source_service = self.app.container\
47+
.market_data_source_service()
48+
ticker_market_data_source = market_data_source_service\
49+
.get_ticker_market_data_source(
50+
symbol="BTC/EUR",
51+
market="BITVAVO"
52+
)
53+
self.assertIsNotNone(ticker_market_data_source)
54+
self.assertEqual("BTC/EUR", ticker_market_data_source.symbol)
55+
self.assertEqual("BITVAVO", ticker_market_data_source.market)
56+
self.assertTrue(
57+
isinstance(ticker_market_data_source, CSVTickerMarketDataSource)
58+
)

version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION = (2, 2, 1, 'alpha', 0)
1+
VERSION = (2, 2, 2, 'alpha', 0)
22

33

44
def get_version(version=None):

0 commit comments

Comments
 (0)