investing-algorithm-framework 3.7.0__py3-none-any.whl → 7.19.15__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of investing-algorithm-framework might be problematic. Click here for more details.
- investing_algorithm_framework/__init__.py +168 -45
- investing_algorithm_framework/app/__init__.py +32 -1
- investing_algorithm_framework/app/algorithm/__init__.py +7 -0
- investing_algorithm_framework/app/algorithm/algorithm.py +239 -0
- investing_algorithm_framework/app/algorithm/algorithm_factory.py +114 -0
- investing_algorithm_framework/app/analysis/__init__.py +15 -0
- investing_algorithm_framework/app/analysis/backtest_data_ranges.py +121 -0
- investing_algorithm_framework/app/analysis/backtest_utils.py +107 -0
- investing_algorithm_framework/app/analysis/permutation.py +116 -0
- investing_algorithm_framework/app/analysis/ranking.py +297 -0
- investing_algorithm_framework/app/app.py +1933 -589
- investing_algorithm_framework/app/app_hook.py +28 -0
- investing_algorithm_framework/app/context.py +1725 -0
- investing_algorithm_framework/app/eventloop.py +590 -0
- investing_algorithm_framework/app/reporting/__init__.py +27 -0
- investing_algorithm_framework/app/reporting/ascii.py +921 -0
- investing_algorithm_framework/app/reporting/backtest_report.py +349 -0
- investing_algorithm_framework/app/reporting/charts/__init__.py +19 -0
- investing_algorithm_framework/app/reporting/charts/entry_exist_signals.py +66 -0
- investing_algorithm_framework/app/reporting/charts/equity_curve.py +37 -0
- investing_algorithm_framework/app/reporting/charts/equity_curve_drawdown.py +74 -0
- investing_algorithm_framework/app/reporting/charts/line_chart.py +11 -0
- investing_algorithm_framework/app/reporting/charts/monthly_returns_heatmap.py +70 -0
- investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +51 -0
- investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +79 -0
- investing_algorithm_framework/app/reporting/charts/yearly_returns_barchart.py +55 -0
- investing_algorithm_framework/app/reporting/generate.py +185 -0
- investing_algorithm_framework/app/reporting/tables/__init__.py +11 -0
- investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +217 -0
- investing_algorithm_framework/app/reporting/tables/stop_loss_table.py +0 -0
- investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +80 -0
- investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +147 -0
- investing_algorithm_framework/app/reporting/tables/trades_table.py +75 -0
- investing_algorithm_framework/app/reporting/tables/utils.py +29 -0
- investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +154 -0
- investing_algorithm_framework/app/stateless/action_handlers/__init__.py +4 -2
- investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +1 -1
- investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +1 -1
- investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +14 -7
- investing_algorithm_framework/app/strategy.py +664 -84
- investing_algorithm_framework/app/task.py +5 -3
- investing_algorithm_framework/app/web/__init__.py +2 -1
- investing_algorithm_framework/app/web/create_app.py +4 -2
- investing_algorithm_framework/cli/__init__.py +0 -0
- investing_algorithm_framework/cli/cli.py +226 -0
- investing_algorithm_framework/cli/deploy_to_aws_lambda.py +501 -0
- investing_algorithm_framework/cli/deploy_to_azure_function.py +718 -0
- investing_algorithm_framework/cli/initialize_app.py +603 -0
- investing_algorithm_framework/cli/templates/.gitignore.template +178 -0
- investing_algorithm_framework/cli/templates/app.py.template +18 -0
- investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +48 -0
- investing_algorithm_framework/cli/templates/app_azure_function.py.template +14 -0
- investing_algorithm_framework/cli/templates/app_web.py.template +18 -0
- investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +22 -0
- investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +92 -0
- investing_algorithm_framework/cli/templates/aws_lambda_readme.md.template +110 -0
- investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +2 -0
- investing_algorithm_framework/cli/templates/azure_function_function_app.py.template +65 -0
- investing_algorithm_framework/cli/templates/azure_function_host.json.template +15 -0
- investing_algorithm_framework/cli/templates/azure_function_local.settings.json.template +8 -0
- investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +3 -0
- investing_algorithm_framework/cli/templates/data_providers.py.template +17 -0
- investing_algorithm_framework/cli/templates/env.example.template +2 -0
- investing_algorithm_framework/cli/templates/env_azure_function.example.template +4 -0
- investing_algorithm_framework/cli/templates/market_data_providers.py.template +9 -0
- investing_algorithm_framework/cli/templates/readme.md.template +135 -0
- investing_algorithm_framework/cli/templates/requirements.txt.template +2 -0
- investing_algorithm_framework/cli/templates/run_backtest.py.template +20 -0
- investing_algorithm_framework/cli/templates/strategy.py.template +124 -0
- investing_algorithm_framework/create_app.py +40 -6
- investing_algorithm_framework/dependency_container.py +72 -56
- investing_algorithm_framework/domain/__init__.py +71 -47
- investing_algorithm_framework/domain/backtesting/__init__.py +21 -0
- investing_algorithm_framework/domain/backtesting/backtest.py +503 -0
- investing_algorithm_framework/domain/backtesting/backtest_date_range.py +96 -0
- investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +242 -0
- investing_algorithm_framework/domain/backtesting/backtest_metrics.py +459 -0
- investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +275 -0
- investing_algorithm_framework/domain/backtesting/backtest_run.py +605 -0
- investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +162 -0
- investing_algorithm_framework/domain/backtesting/combine_backtests.py +280 -0
- investing_algorithm_framework/domain/config.py +59 -91
- investing_algorithm_framework/domain/constants.py +13 -38
- investing_algorithm_framework/domain/data_provider.py +334 -0
- investing_algorithm_framework/domain/data_structures.py +3 -2
- investing_algorithm_framework/domain/exceptions.py +51 -1
- investing_algorithm_framework/domain/models/__init__.py +17 -12
- investing_algorithm_framework/domain/models/data/__init__.py +7 -0
- investing_algorithm_framework/domain/models/data/data_source.py +214 -0
- investing_algorithm_framework/domain/models/data/data_type.py +46 -0
- investing_algorithm_framework/domain/models/event.py +35 -0
- investing_algorithm_framework/domain/models/market/market_credential.py +55 -1
- investing_algorithm_framework/domain/models/order/order.py +77 -83
- investing_algorithm_framework/domain/models/order/order_status.py +2 -2
- investing_algorithm_framework/domain/models/order/order_type.py +1 -3
- investing_algorithm_framework/domain/models/portfolio/portfolio.py +81 -3
- investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +26 -3
- investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +108 -11
- investing_algorithm_framework/domain/models/position/__init__.py +2 -1
- investing_algorithm_framework/domain/models/position/position.py +12 -0
- investing_algorithm_framework/domain/models/position/position_size.py +41 -0
- investing_algorithm_framework/domain/models/risk_rules/__init__.py +7 -0
- investing_algorithm_framework/domain/models/risk_rules/stop_loss_rule.py +51 -0
- investing_algorithm_framework/domain/models/risk_rules/take_profit_rule.py +55 -0
- investing_algorithm_framework/domain/models/snapshot_interval.py +45 -0
- investing_algorithm_framework/domain/models/strategy_profile.py +19 -151
- investing_algorithm_framework/domain/models/time_frame.py +37 -0
- investing_algorithm_framework/domain/models/time_interval.py +33 -0
- investing_algorithm_framework/domain/models/time_unit.py +66 -2
- investing_algorithm_framework/domain/models/trade/__init__.py +8 -1
- investing_algorithm_framework/domain/models/trade/trade.py +295 -171
- investing_algorithm_framework/domain/models/trade/trade_status.py +9 -2
- investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +332 -0
- investing_algorithm_framework/domain/models/trade/trade_take_profit.py +365 -0
- investing_algorithm_framework/domain/order_executor.py +112 -0
- investing_algorithm_framework/domain/portfolio_provider.py +118 -0
- investing_algorithm_framework/domain/services/__init__.py +2 -9
- investing_algorithm_framework/domain/services/portfolios/portfolio_sync_service.py +0 -6
- investing_algorithm_framework/domain/services/state_handler.py +38 -0
- investing_algorithm_framework/domain/strategy.py +1 -29
- investing_algorithm_framework/domain/utils/__init__.py +12 -7
- investing_algorithm_framework/domain/utils/custom_tqdm.py +22 -0
- investing_algorithm_framework/domain/utils/dates.py +57 -0
- investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +19 -0
- investing_algorithm_framework/domain/utils/polars.py +53 -0
- investing_algorithm_framework/domain/utils/random.py +29 -0
- investing_algorithm_framework/download_data.py +108 -0
- investing_algorithm_framework/infrastructure/__init__.py +31 -18
- investing_algorithm_framework/infrastructure/data_providers/__init__.py +36 -0
- investing_algorithm_framework/infrastructure/data_providers/ccxt.py +1143 -0
- investing_algorithm_framework/infrastructure/data_providers/csv.py +568 -0
- investing_algorithm_framework/infrastructure/data_providers/pandas.py +599 -0
- investing_algorithm_framework/infrastructure/database/__init__.py +6 -2
- investing_algorithm_framework/infrastructure/database/sql_alchemy.py +86 -12
- investing_algorithm_framework/infrastructure/models/__init__.py +6 -11
- investing_algorithm_framework/infrastructure/models/order/__init__.py +2 -1
- investing_algorithm_framework/infrastructure/models/order/order.py +35 -49
- investing_algorithm_framework/infrastructure/models/order/order_metadata.py +44 -0
- investing_algorithm_framework/infrastructure/models/order_trade_association.py +10 -0
- investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +1 -1
- investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +8 -0
- investing_algorithm_framework/infrastructure/models/portfolio/{portfolio.py → sql_portfolio.py} +17 -5
- investing_algorithm_framework/infrastructure/models/trades/__init__.py +9 -0
- investing_algorithm_framework/infrastructure/models/trades/trade.py +130 -0
- investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +59 -0
- investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +55 -0
- investing_algorithm_framework/infrastructure/order_executors/__init__.py +21 -0
- investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +28 -0
- investing_algorithm_framework/infrastructure/order_executors/ccxt_order_executor.py +200 -0
- investing_algorithm_framework/infrastructure/portfolio_providers/__init__.py +19 -0
- investing_algorithm_framework/infrastructure/portfolio_providers/ccxt_portfolio_provider.py +199 -0
- investing_algorithm_framework/infrastructure/repositories/__init__.py +8 -0
- investing_algorithm_framework/infrastructure/repositories/order_metadata_repository.py +17 -0
- investing_algorithm_framework/infrastructure/repositories/order_repository.py +5 -0
- investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +1 -1
- investing_algorithm_framework/infrastructure/repositories/position_repository.py +11 -0
- investing_algorithm_framework/infrastructure/repositories/repository.py +81 -27
- investing_algorithm_framework/infrastructure/repositories/trade_repository.py +71 -0
- investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +29 -0
- investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +29 -0
- investing_algorithm_framework/infrastructure/services/__init__.py +4 -4
- investing_algorithm_framework/infrastructure/services/aws/__init__.py +6 -0
- investing_algorithm_framework/infrastructure/services/aws/state_handler.py +113 -0
- investing_algorithm_framework/infrastructure/services/azure/__init__.py +5 -0
- investing_algorithm_framework/infrastructure/services/azure/state_handler.py +158 -0
- investing_algorithm_framework/services/__init__.py +113 -16
- investing_algorithm_framework/services/backtesting/__init__.py +0 -7
- investing_algorithm_framework/services/backtesting/backtest_service.py +566 -359
- investing_algorithm_framework/services/configuration_service.py +77 -11
- investing_algorithm_framework/services/data_providers/__init__.py +5 -0
- investing_algorithm_framework/services/data_providers/data_provider_service.py +850 -0
- investing_algorithm_framework/services/market_credential_service.py +16 -1
- investing_algorithm_framework/services/metrics/__init__.py +114 -0
- investing_algorithm_framework/services/metrics/alpha.py +0 -0
- investing_algorithm_framework/services/metrics/beta.py +0 -0
- investing_algorithm_framework/services/metrics/cagr.py +60 -0
- investing_algorithm_framework/services/metrics/calmar_ratio.py +40 -0
- investing_algorithm_framework/services/metrics/drawdown.py +181 -0
- investing_algorithm_framework/services/metrics/equity_curve.py +24 -0
- investing_algorithm_framework/services/metrics/exposure.py +210 -0
- investing_algorithm_framework/services/metrics/generate.py +358 -0
- investing_algorithm_framework/services/metrics/mean_daily_return.py +83 -0
- investing_algorithm_framework/services/metrics/profit_factor.py +165 -0
- investing_algorithm_framework/services/metrics/recovery.py +113 -0
- investing_algorithm_framework/services/metrics/returns.py +452 -0
- investing_algorithm_framework/services/metrics/risk_free_rate.py +28 -0
- investing_algorithm_framework/services/metrics/sharpe_ratio.py +137 -0
- investing_algorithm_framework/services/metrics/sortino_ratio.py +74 -0
- investing_algorithm_framework/services/metrics/standard_deviation.py +157 -0
- investing_algorithm_framework/services/metrics/trades.py +500 -0
- investing_algorithm_framework/services/metrics/treynor_ratio.py +0 -0
- investing_algorithm_framework/services/metrics/ulcer.py +0 -0
- investing_algorithm_framework/services/metrics/value_at_risk.py +0 -0
- investing_algorithm_framework/services/metrics/volatility.py +97 -0
- investing_algorithm_framework/services/metrics/win_rate.py +177 -0
- investing_algorithm_framework/services/order_service/__init__.py +3 -1
- investing_algorithm_framework/services/order_service/order_backtest_service.py +76 -89
- investing_algorithm_framework/services/order_service/order_executor_lookup.py +110 -0
- investing_algorithm_framework/services/order_service/order_service.py +407 -326
- investing_algorithm_framework/services/portfolios/__init__.py +3 -1
- investing_algorithm_framework/services/portfolios/backtest_portfolio_service.py +37 -3
- investing_algorithm_framework/services/portfolios/portfolio_configuration_service.py +22 -8
- investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +106 -0
- investing_algorithm_framework/services/portfolios/portfolio_service.py +96 -28
- investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +97 -28
- investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +116 -313
- investing_algorithm_framework/services/positions/__init__.py +7 -0
- investing_algorithm_framework/services/positions/position_service.py +210 -0
- investing_algorithm_framework/services/repository_service.py +8 -2
- investing_algorithm_framework/services/trade_order_evaluator/__init__.py +9 -0
- investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +113 -0
- investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +51 -0
- investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +80 -0
- investing_algorithm_framework/services/trade_service/__init__.py +7 -1
- investing_algorithm_framework/services/trade_service/trade_service.py +1013 -315
- investing_algorithm_framework/services/trade_service/trade_stop_loss_service.py +39 -0
- investing_algorithm_framework/services/trade_service/trade_take_profit_service.py +41 -0
- investing_algorithm_framework-7.19.15.dist-info/METADATA +537 -0
- investing_algorithm_framework-7.19.15.dist-info/RECORD +263 -0
- investing_algorithm_framework-7.19.15.dist-info/entry_points.txt +3 -0
- investing_algorithm_framework/app/algorithm.py +0 -1105
- investing_algorithm_framework/domain/graphs.py +0 -382
- investing_algorithm_framework/domain/metrics/__init__.py +0 -6
- investing_algorithm_framework/domain/models/backtesting/__init__.py +0 -11
- investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py +0 -43
- investing_algorithm_framework/domain/models/backtesting/backtest_position.py +0 -120
- investing_algorithm_framework/domain/models/backtesting/backtest_report.py +0 -580
- investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py +0 -243
- investing_algorithm_framework/domain/models/trading_data_types.py +0 -47
- investing_algorithm_framework/domain/models/trading_time_frame.py +0 -223
- investing_algorithm_framework/domain/services/market_data_sources.py +0 -344
- investing_algorithm_framework/domain/services/market_service.py +0 -153
- investing_algorithm_framework/domain/singleton.py +0 -9
- investing_algorithm_framework/domain/utils/backtesting.py +0 -472
- investing_algorithm_framework/infrastructure/models/market_data_sources/__init__.py +0 -12
- investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py +0 -559
- investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +0 -254
- investing_algorithm_framework/infrastructure/models/market_data_sources/us_treasury_yield.py +0 -47
- investing_algorithm_framework/infrastructure/services/market_service/__init__.py +0 -5
- investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py +0 -455
- investing_algorithm_framework/infrastructure/services/performance_service/__init__.py +0 -7
- investing_algorithm_framework/infrastructure/services/performance_service/backtest_performance_service.py +0 -2
- investing_algorithm_framework/infrastructure/services/performance_service/performance_service.py +0 -350
- investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py +0 -53
- investing_algorithm_framework/services/backtesting/graphs.py +0 -61
- investing_algorithm_framework/services/market_data_source_service/__init__.py +0 -8
- investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py +0 -150
- investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py +0 -189
- investing_algorithm_framework/services/position_service.py +0 -31
- investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -264
- investing_algorithm_framework-3.7.0.dist-info/METADATA +0 -339
- investing_algorithm_framework-3.7.0.dist-info/RECORD +0 -147
- /investing_algorithm_framework/{domain → services}/metrics/price_efficiency.py +0 -0
- /investing_algorithm_framework/services/{position_snapshot_service.py → positions/position_snapshot_service.py} +0 -0
- {investing_algorithm_framework-3.7.0.dist-info → investing_algorithm_framework-7.19.15.dist-info}/LICENSE +0 -0
- {investing_algorithm_framework-3.7.0.dist-info → investing_algorithm_framework-7.19.15.dist-info}/WHEEL +0 -0
investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py
DELETED
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
from typing import List
|
|
2
|
-
|
|
3
|
-
from investing_algorithm_framework.domain import MarketService, \
|
|
4
|
-
MarketDataSource, OHLCVMarketDataSource, TickerMarketDataSource, \
|
|
5
|
-
OrderBookMarketDataSource, TimeFrame
|
|
6
|
-
from investing_algorithm_framework.services.market_credential_service \
|
|
7
|
-
import MarketCredentialService
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
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
|
-
"""
|
|
20
|
-
_market_data_sources: List[MarketDataSource] = []
|
|
21
|
-
|
|
22
|
-
def __init__(
|
|
23
|
-
self,
|
|
24
|
-
market_service: MarketService,
|
|
25
|
-
market_credential_service: MarketCredentialService,
|
|
26
|
-
market_data_sources: List[MarketDataSource] = None,
|
|
27
|
-
):
|
|
28
|
-
|
|
29
|
-
if market_data_sources is not None:
|
|
30
|
-
self._market_data_sources: List[MarketDataSource] \
|
|
31
|
-
= market_data_sources
|
|
32
|
-
|
|
33
|
-
self._market_service: MarketService = market_service
|
|
34
|
-
self._market_credential_service: MarketCredentialService = \
|
|
35
|
-
market_credential_service
|
|
36
|
-
|
|
37
|
-
def get_ticker(self, symbol, market=None):
|
|
38
|
-
ticker_market_data_source = self.get_ticker_market_data_source(
|
|
39
|
-
symbol=symbol, market=market
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
if ticker_market_data_source is not None:
|
|
43
|
-
return ticker_market_data_source.get_data(
|
|
44
|
-
market_credential_service=self._market_credential_service
|
|
45
|
-
)
|
|
46
|
-
return self._market_service.get_ticker(symbol, market)
|
|
47
|
-
|
|
48
|
-
def get_order_book(self, symbol, market=None):
|
|
49
|
-
order_book_market_data_source = self.get_order_book_market_data_source(
|
|
50
|
-
symbol=symbol, market=market
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
if order_book_market_data_source is not None:
|
|
54
|
-
return order_book_market_data_source.get_data(
|
|
55
|
-
market_credential_service=self._market_credential_service
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
return self._market_service.get_order_book(symbol, market)
|
|
59
|
-
|
|
60
|
-
def get_ohlcv(
|
|
61
|
-
self,
|
|
62
|
-
symbol,
|
|
63
|
-
from_timestamp,
|
|
64
|
-
time_frame,
|
|
65
|
-
market=None,
|
|
66
|
-
to_timestamp=None
|
|
67
|
-
):
|
|
68
|
-
ohlcv_market_data_source = self.get_ohlcv_market_data_source(
|
|
69
|
-
symbol=symbol, market=market, time_frame=time_frame
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
if ohlcv_market_data_source is not None:
|
|
73
|
-
return ohlcv_market_data_source.get_data(
|
|
74
|
-
from_timestamp=from_timestamp,
|
|
75
|
-
to_timestamp=to_timestamp,
|
|
76
|
-
market_credential_service=self._market_credential_service
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
return self._market_service.get_ohlcv(
|
|
80
|
-
symbol=symbol,
|
|
81
|
-
time_frame=time_frame,
|
|
82
|
-
from_timestamp=from_timestamp,
|
|
83
|
-
market=market,
|
|
84
|
-
to_timestamp=to_timestamp
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
def get_data(self, identifier):
|
|
88
|
-
for market_data_source in self._market_data_sources:
|
|
89
|
-
if market_data_source.get_identifier() == identifier:
|
|
90
|
-
return market_data_source.get_data(
|
|
91
|
-
market_credential_service=self._market_credential_service
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
def get_ticker_market_data_source(self, symbol, market=None):
|
|
95
|
-
|
|
96
|
-
if self.market_data_sources is not None:
|
|
97
|
-
for market_data_source in self._market_data_sources:
|
|
98
|
-
if isinstance(market_data_source, TickerMarketDataSource):
|
|
99
|
-
|
|
100
|
-
if market is not None:
|
|
101
|
-
if market_data_source.market.lower() == market.lower()\
|
|
102
|
-
and market_data_source.symbol.lower() \
|
|
103
|
-
== symbol.lower():
|
|
104
|
-
return market_data_source
|
|
105
|
-
else:
|
|
106
|
-
if market_data_source.symbol.lower() \
|
|
107
|
-
== symbol.lower():
|
|
108
|
-
return market_data_source
|
|
109
|
-
|
|
110
|
-
return None
|
|
111
|
-
|
|
112
|
-
def get_ohlcv_market_data_source(
|
|
113
|
-
self, symbol, time_frame=None, market=None
|
|
114
|
-
):
|
|
115
|
-
|
|
116
|
-
if time_frame is not None:
|
|
117
|
-
time_frame = TimeFrame.from_value(time_frame)
|
|
118
|
-
|
|
119
|
-
if self.market_data_sources is not None:
|
|
120
|
-
|
|
121
|
-
for market_data_source in self._market_data_sources:
|
|
122
|
-
if isinstance(market_data_source, OHLCVMarketDataSource):
|
|
123
|
-
|
|
124
|
-
if market is not None and time_frame is not None:
|
|
125
|
-
|
|
126
|
-
if market_data_source.market.lower() == market.lower()\
|
|
127
|
-
and market_data_source.symbol.lower() \
|
|
128
|
-
== symbol.lower() and \
|
|
129
|
-
market_data_source.timeframe == time_frame:
|
|
130
|
-
return market_data_source
|
|
131
|
-
elif market is not None:
|
|
132
|
-
if market_data_source.market.lower() == market.lower()\
|
|
133
|
-
and market_data_source.symbol.lower() \
|
|
134
|
-
== symbol.lower():
|
|
135
|
-
return market_data_source
|
|
136
|
-
elif time_frame is not None:
|
|
137
|
-
if market_data_source.symbol.lower() \
|
|
138
|
-
== symbol.lower() and \
|
|
139
|
-
market_data_source.timeframe == time_frame:
|
|
140
|
-
return market_data_source
|
|
141
|
-
else:
|
|
142
|
-
if market_data_source.symbol.lower() \
|
|
143
|
-
== symbol.lower():
|
|
144
|
-
return market_data_source
|
|
145
|
-
|
|
146
|
-
return None
|
|
147
|
-
|
|
148
|
-
def get_order_book_market_data_source(self, symbol, market=None):
|
|
149
|
-
|
|
150
|
-
if self.market_data_sources is not None:
|
|
151
|
-
for market_data_source in self._market_data_sources:
|
|
152
|
-
if isinstance(market_data_source, OrderBookMarketDataSource):
|
|
153
|
-
|
|
154
|
-
if market is not None:
|
|
155
|
-
if market_data_source.market.lower() == market.lower()\
|
|
156
|
-
and market_data_source.symbol.lower() \
|
|
157
|
-
== symbol.lower():
|
|
158
|
-
return market_data_source
|
|
159
|
-
else:
|
|
160
|
-
if market_data_source.symbol.lower() \
|
|
161
|
-
== symbol.lower():
|
|
162
|
-
return market_data_source
|
|
163
|
-
|
|
164
|
-
return None
|
|
165
|
-
|
|
166
|
-
@property
|
|
167
|
-
def market_data_sources(self):
|
|
168
|
-
return self._market_data_sources
|
|
169
|
-
|
|
170
|
-
@market_data_sources.setter
|
|
171
|
-
def market_data_sources(self, market_data_sources):
|
|
172
|
-
self._market_data_sources = market_data_sources
|
|
173
|
-
|
|
174
|
-
def add(self, market_data_source):
|
|
175
|
-
|
|
176
|
-
# Check if there is already a market data source with the same
|
|
177
|
-
# identifier
|
|
178
|
-
for existing_market_data_source in self._market_data_sources:
|
|
179
|
-
if existing_market_data_source.get_identifier() == \
|
|
180
|
-
market_data_source.get_identifier():
|
|
181
|
-
return
|
|
182
|
-
|
|
183
|
-
self._market_data_sources.append(market_data_source)
|
|
184
|
-
|
|
185
|
-
def get_market_data_sources(self):
|
|
186
|
-
return self._market_data_sources
|
|
187
|
-
|
|
188
|
-
def has_ticker_market_data_source(self, symbol, market=None):
|
|
189
|
-
return self.get_ticker_market_data_source(symbol, market) is not None
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
from investing_algorithm_framework.domain import MarketService
|
|
2
|
-
from investing_algorithm_framework.services.repository_service import \
|
|
3
|
-
RepositoryService
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class PositionService(RepositoryService):
|
|
7
|
-
|
|
8
|
-
def __init__(
|
|
9
|
-
self,
|
|
10
|
-
repository,
|
|
11
|
-
order_repository,
|
|
12
|
-
market_service: MarketService,
|
|
13
|
-
market_credential_service
|
|
14
|
-
):
|
|
15
|
-
super().__init__(repository)
|
|
16
|
-
self._market_service: MarketService = market_service
|
|
17
|
-
self._market_credentials_service = market_credential_service
|
|
18
|
-
self._order_repository = order_repository
|
|
19
|
-
|
|
20
|
-
def close_position(self, position_id, portfolio):
|
|
21
|
-
self._market_service.market_data_credentials = \
|
|
22
|
-
self._market_credentials_service.get_all()
|
|
23
|
-
position = self.get(position_id)
|
|
24
|
-
|
|
25
|
-
if position.amount > 0:
|
|
26
|
-
self._market_service.create_market_sell_order(
|
|
27
|
-
position.symbol,
|
|
28
|
-
portfolio.get_trading_symbol(),
|
|
29
|
-
position.amount,
|
|
30
|
-
market=portfolio.get_market(),
|
|
31
|
-
)
|
|
@@ -1,264 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from datetime import datetime
|
|
3
|
-
|
|
4
|
-
import schedule
|
|
5
|
-
|
|
6
|
-
from investing_algorithm_framework.domain import StoppableThread, TimeUnit, \
|
|
7
|
-
OperationalException, MarketDataSource
|
|
8
|
-
from investing_algorithm_framework.services.market_data_source_service \
|
|
9
|
-
import MarketDataSourceService
|
|
10
|
-
|
|
11
|
-
logger = logging.getLogger("investing_algorithm_framework")
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class StrategyOrchestratorService:
|
|
15
|
-
"""
|
|
16
|
-
Service that orchestrates the execution of strategies and tasks
|
|
17
|
-
|
|
18
|
-
Attributes:
|
|
19
|
-
- history: dict
|
|
20
|
-
A dictionary that keeps track of the last time a strategy or task was
|
|
21
|
-
run
|
|
22
|
-
- _strategies: list
|
|
23
|
-
A list of strategies
|
|
24
|
-
- _tasks: list
|
|
25
|
-
A list of tasks
|
|
26
|
-
- threads: list
|
|
27
|
-
A list of threads that are currently running
|
|
28
|
-
- iterations: int
|
|
29
|
-
The number of iterations that have been run
|
|
30
|
-
- max_iterations: int
|
|
31
|
-
The maximum number of iterations that can be run
|
|
32
|
-
- market_data_source_service: MarketDataSourceService
|
|
33
|
-
The service that provides market data
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
def __init__(self, market_data_source_service: MarketDataSourceService):
|
|
37
|
-
self.history = {}
|
|
38
|
-
self._strategies = []
|
|
39
|
-
self._tasks = []
|
|
40
|
-
self.threads = []
|
|
41
|
-
self.iterations = 0
|
|
42
|
-
self.max_iterations = -1
|
|
43
|
-
self.clear()
|
|
44
|
-
self.market_data_source_service: MarketDataSourceService \
|
|
45
|
-
= market_data_source_service
|
|
46
|
-
|
|
47
|
-
def cleanup_threads(self):
|
|
48
|
-
|
|
49
|
-
for stoppable in self.threads:
|
|
50
|
-
if not stoppable.is_alive():
|
|
51
|
-
# get results from thread
|
|
52
|
-
stoppable.done = True
|
|
53
|
-
self.threads = [t for t in self.threads if not t.done]
|
|
54
|
-
|
|
55
|
-
def run_strategy(self, strategy, algorithm, sync=False):
|
|
56
|
-
self.cleanup_threads()
|
|
57
|
-
matching_thread = next(
|
|
58
|
-
(t for t in self.threads if t.name == strategy.worker_id),
|
|
59
|
-
None
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
# Don't run a strategy that is already running
|
|
63
|
-
if matching_thread:
|
|
64
|
-
return
|
|
65
|
-
|
|
66
|
-
market_data = {}
|
|
67
|
-
|
|
68
|
-
if strategy.market_data_sources is not None \
|
|
69
|
-
and len(strategy.market_data_sources) > 0:
|
|
70
|
-
|
|
71
|
-
for data_id in strategy.market_data_sources:
|
|
72
|
-
|
|
73
|
-
if isinstance(data_id, MarketDataSource):
|
|
74
|
-
market_data[data_id.get_identifier()] = \
|
|
75
|
-
self.market_data_source_service\
|
|
76
|
-
.get_data(identifier=data_id.get_identifier())
|
|
77
|
-
else:
|
|
78
|
-
market_data[data_id] = \
|
|
79
|
-
self.market_data_source_service \
|
|
80
|
-
.get_data(identifier=data_id)
|
|
81
|
-
|
|
82
|
-
logger.info(f"Running strategy {strategy.worker_id}")
|
|
83
|
-
|
|
84
|
-
if sync:
|
|
85
|
-
strategy.run_strategy(
|
|
86
|
-
market_data=market_data, algorithm=algorithm
|
|
87
|
-
)
|
|
88
|
-
else:
|
|
89
|
-
self.iterations += 1
|
|
90
|
-
thread = StoppableThread(
|
|
91
|
-
target=strategy.run_strategy,
|
|
92
|
-
kwargs={
|
|
93
|
-
"market_data": market_data,
|
|
94
|
-
"algorithm": algorithm
|
|
95
|
-
}
|
|
96
|
-
)
|
|
97
|
-
thread.name = strategy.worker_id
|
|
98
|
-
thread.start()
|
|
99
|
-
self.threads.append(thread)
|
|
100
|
-
|
|
101
|
-
self.history[strategy.worker_id] = {"last_run": datetime.utcnow()}
|
|
102
|
-
|
|
103
|
-
def run_task(self, task, algorithm, sync=False):
|
|
104
|
-
self.cleanup_threads()
|
|
105
|
-
|
|
106
|
-
matching_thread = next(
|
|
107
|
-
(t for t in self.threads if t.name == task.worker_id),
|
|
108
|
-
None
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
# Don't run a strategy that is already running
|
|
112
|
-
if matching_thread:
|
|
113
|
-
return
|
|
114
|
-
|
|
115
|
-
logger.info(f"Running task {task.worker_id}")
|
|
116
|
-
|
|
117
|
-
if sync:
|
|
118
|
-
task.run(algorithm=algorithm)
|
|
119
|
-
else:
|
|
120
|
-
self.iterations += 1
|
|
121
|
-
thread = StoppableThread(
|
|
122
|
-
target=task.run,
|
|
123
|
-
kwargs={"algorithm": algorithm}
|
|
124
|
-
)
|
|
125
|
-
thread.name = task.worker_id
|
|
126
|
-
thread.start()
|
|
127
|
-
self.threads.append(thread)
|
|
128
|
-
|
|
129
|
-
self.history[task.worker_id] = {"last_run": datetime.utcnow()}
|
|
130
|
-
|
|
131
|
-
def start(self, algorithm, number_of_iterations=None):
|
|
132
|
-
"""
|
|
133
|
-
F
|
|
134
|
-
|
|
135
|
-
"""
|
|
136
|
-
self.max_iterations = number_of_iterations
|
|
137
|
-
|
|
138
|
-
for strategy in self.strategies:
|
|
139
|
-
if TimeUnit.SECOND.equals(strategy.time_unit):
|
|
140
|
-
schedule.every(strategy.interval)\
|
|
141
|
-
.seconds.do(self.run_strategy, strategy, algorithm)
|
|
142
|
-
elif TimeUnit.MINUTE.equals(strategy.time_unit):
|
|
143
|
-
schedule.every(strategy.interval)\
|
|
144
|
-
.minutes.do(self.run_strategy, strategy, algorithm)
|
|
145
|
-
elif TimeUnit.HOUR.equals(strategy.time_unit):
|
|
146
|
-
schedule.every(strategy.interval)\
|
|
147
|
-
.hours.do(self.run_strategy, strategy, algorithm)
|
|
148
|
-
|
|
149
|
-
for task in self.tasks:
|
|
150
|
-
if TimeUnit.SECOND.equals(task.time_unit):
|
|
151
|
-
schedule.every(task.interval)\
|
|
152
|
-
.seconds.do(self.run_task, task, algorithm)
|
|
153
|
-
elif TimeUnit.MINUTE.equals(task.time_unit):
|
|
154
|
-
schedule.every(task.interval)\
|
|
155
|
-
.minutes.do(self.run_task, task, algorithm)
|
|
156
|
-
elif TimeUnit.HOUR.equals(task.time_unit):
|
|
157
|
-
schedule.every(task.interval)\
|
|
158
|
-
.hours.do(self.run_task, task, algorithm)
|
|
159
|
-
|
|
160
|
-
def stop(self):
|
|
161
|
-
for thread in self.threads:
|
|
162
|
-
thread.stop()
|
|
163
|
-
|
|
164
|
-
schedule.clear()
|
|
165
|
-
|
|
166
|
-
def clear(self):
|
|
167
|
-
self.threads = []
|
|
168
|
-
schedule.clear()
|
|
169
|
-
|
|
170
|
-
def get_strategies(self, identifiers=None):
|
|
171
|
-
if identifiers is None:
|
|
172
|
-
return self.strategies
|
|
173
|
-
|
|
174
|
-
strategies = []
|
|
175
|
-
for strategy in self.strategies:
|
|
176
|
-
if strategy.worker_id in identifiers:
|
|
177
|
-
strategies.append(strategy)
|
|
178
|
-
|
|
179
|
-
return strategies
|
|
180
|
-
|
|
181
|
-
def get_tasks(self):
|
|
182
|
-
return self._tasks
|
|
183
|
-
|
|
184
|
-
def get_jobs(self):
|
|
185
|
-
return schedule.jobs
|
|
186
|
-
|
|
187
|
-
def run_pending_jobs(self):
|
|
188
|
-
if self.max_iterations is not None and \
|
|
189
|
-
self.max_iterations != -1 and \
|
|
190
|
-
self.iterations >= self.max_iterations:
|
|
191
|
-
self.clear()
|
|
192
|
-
else:
|
|
193
|
-
schedule.run_pending()
|
|
194
|
-
|
|
195
|
-
def add_strategy(self, strategy):
|
|
196
|
-
|
|
197
|
-
if strategy.worker_id not in self._strategies:
|
|
198
|
-
self._strategies.append(strategy)
|
|
199
|
-
else:
|
|
200
|
-
raise OperationalException(
|
|
201
|
-
"Strategy already exists with the same name"
|
|
202
|
-
)
|
|
203
|
-
|
|
204
|
-
def add_strategies(self, strategies):
|
|
205
|
-
has_duplicates = False
|
|
206
|
-
|
|
207
|
-
for i in range(len(strategies)):
|
|
208
|
-
for j in range(i + 1, len(strategies)):
|
|
209
|
-
if strategies[i].worker_id == strategies[j].worker_id:
|
|
210
|
-
has_duplicates = True
|
|
211
|
-
break
|
|
212
|
-
|
|
213
|
-
if has_duplicates:
|
|
214
|
-
raise OperationalException(
|
|
215
|
-
"There are duplicate strategies with the same name"
|
|
216
|
-
)
|
|
217
|
-
|
|
218
|
-
self.strategies = strategies
|
|
219
|
-
|
|
220
|
-
def add_tasks(self, tasks):
|
|
221
|
-
has_duplicates = False
|
|
222
|
-
|
|
223
|
-
for i in range(len(tasks)):
|
|
224
|
-
for j in range(i + 1, len(tasks)):
|
|
225
|
-
if tasks[i].worker_id == tasks[j].worker_id:
|
|
226
|
-
has_duplicates = True
|
|
227
|
-
break
|
|
228
|
-
|
|
229
|
-
if has_duplicates:
|
|
230
|
-
raise OperationalException(
|
|
231
|
-
"There are duplicate tasks with the same name"
|
|
232
|
-
)
|
|
233
|
-
|
|
234
|
-
self.tasks = tasks
|
|
235
|
-
|
|
236
|
-
@property
|
|
237
|
-
def strategies(self):
|
|
238
|
-
return self._strategies
|
|
239
|
-
|
|
240
|
-
@strategies.setter
|
|
241
|
-
def strategies(self, strategies):
|
|
242
|
-
self._strategies = strategies
|
|
243
|
-
|
|
244
|
-
@property
|
|
245
|
-
def tasks(self):
|
|
246
|
-
return self._tasks
|
|
247
|
-
|
|
248
|
-
@tasks.setter
|
|
249
|
-
def tasks(self, tasks):
|
|
250
|
-
self._tasks = tasks
|
|
251
|
-
|
|
252
|
-
@property
|
|
253
|
-
def running(self):
|
|
254
|
-
if len(self.strategies) == 0 and len(self.tasks) == 0:
|
|
255
|
-
return False
|
|
256
|
-
|
|
257
|
-
if self.max_iterations == -1:
|
|
258
|
-
return True
|
|
259
|
-
|
|
260
|
-
return self.max_iterations is None \
|
|
261
|
-
or self.iterations < self.max_iterations
|
|
262
|
-
|
|
263
|
-
def has_run(self, worker_id):
|
|
264
|
-
return worker_id in self.history
|