investing-algorithm-framework 2.3.2__tar.gz → 2.5.0__tar.gz
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.
- {investing_algorithm_framework-2.3.2/investing_algorithm_framework.egg-info → investing_algorithm_framework-2.5.0}/PKG-INFO +25 -35
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/README.md +1 -1
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/__init__.py +1 -1
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/algorithm.py +70 -223
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/app.py +68 -22
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/stateless/action_handlers/__init__.py +2 -1
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/strategy.py +24 -4
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/create_app.py +2 -1
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/dependency_container.py +14 -3
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/__init__.py +5 -5
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/config.py +6 -5
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/__init__.py +2 -2
- investing_algorithm_framework-2.5.0/investing_algorithm_framework/domain/models/backtesting/__init__.py +6 -0
- investing_algorithm_framework-2.3.2/investing_algorithm_framework/domain/models/backtest_profile.py → investing_algorithm_framework-2.5.0/investing_algorithm_framework/domain/models/backtesting/backtest_report.py +53 -4
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/order/order.py +45 -4
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +1 -1
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/position/position_snapshot.py +0 -2
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/trade.py +7 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/trading_time_frame.py +1 -1
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/services/market_data_sources.py +4 -3
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/services/market_service.py +4 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/utils/backtesting.py +78 -20
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/market_data_sources/__init__.py +1 -1
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py +28 -12
- investing_algorithm_framework-2.5.0/investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +177 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/portfolio/portfolio.py +0 -1
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +0 -2
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/position/position_snapshot.py +3 -1
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +1 -1
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/services/performance_service/performance_service.py +11 -6
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/__init__.py +6 -3
- investing_algorithm_framework-2.5.0/investing_algorithm_framework/services/backtesting/__init__.py +8 -0
- investing_algorithm_framework-2.5.0/investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py +37 -0
- {investing_algorithm_framework-2.3.2/investing_algorithm_framework/services → investing_algorithm_framework-2.5.0/investing_algorithm_framework/services/backtesting}/backtest_service.py +77 -45
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/market_data_source_service/__init__.py +1 -1
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py +16 -14
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py +0 -1
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/order_service/order_backtest_service.py +2 -1
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/order_service/order_service.py +36 -17
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/portfolio_service/portfolio_service.py +136 -96
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/portfolio_snapshot_service.py +0 -1
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/position_service.py +2 -1
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -2
- investing_algorithm_framework-2.5.0/investing_algorithm_framework/services/trade_service/__init__.py +3 -0
- investing_algorithm_framework-2.5.0/investing_algorithm_framework/services/trade_service/trade_service.py +283 -0
- investing_algorithm_framework-2.5.0/pyproject.toml +32 -0
- investing_algorithm_framework-2.3.2/AUTHORS.md +0 -8
- investing_algorithm_framework-2.3.2/PKG-INFO +0 -353
- investing_algorithm_framework-2.3.2/investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +0 -177
- investing_algorithm_framework-2.3.2/investing_algorithm_framework.egg-info/SOURCES.txt +0 -134
- investing_algorithm_framework-2.3.2/investing_algorithm_framework.egg-info/dependency_links.txt +0 -1
- investing_algorithm_framework-2.3.2/investing_algorithm_framework.egg-info/requires.txt +0 -16
- investing_algorithm_framework-2.3.2/investing_algorithm_framework.egg-info/top_level.txt +0 -1
- investing_algorithm_framework-2.3.2/setup.cfg +0 -7
- investing_algorithm_framework-2.3.2/setup.py +0 -39
- investing_algorithm_framework-2.3.2/tests/test_create_app.py +0 -68
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/LICENSE +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/stateless/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/stateless/exception_handler.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/task.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/controllers/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/controllers/orders.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/controllers/portfolio.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/controllers/positions.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/create_app.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/error_handler.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/responses.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/run_strategies.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/schemas/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/schemas/order.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/schemas/portfolio.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/schemas/position.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/app/web/setup_cors.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/constants.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/data_structures.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/decimal_parsing.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/exceptions.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/base_model.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/market/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/market/market_credential.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/order/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/order/order_fee.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/order/order_side.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/order/order_status.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/order/order_type.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/portfolio/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/portfolio/portfolio.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/position/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/position/position.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/strategy_profile.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/time_frame.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/time_interval.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/time_unit.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/models/trading_data_types.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/services/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/singleton.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/stateless_actions.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/strategy.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/utils/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/utils/csv.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/utils/random.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/utils/signatures.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/utils/stoppable_thread.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/domain/utils/synchronized.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/database/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/database/sql_alchemy.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/decimal_parser.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/model_extension.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/order/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/order/order.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/order/order_fee.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/position/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/models/position/position.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/repositories/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/repositories/order_fee_repository.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/repositories/order_repository.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/repositories/portfolio_snapshot_repository.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/repositories/position_repository.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/repositories/position_snapshot_repository.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/repositories/repository.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/services/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/services/market_service/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/services/performance_service/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/infrastructure/services/performance_service/backtest_performance_service.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/configuration_service.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/market_credential_service.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/order_service/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/portfolio_configuration_service.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/portfolio_service/__init__.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/portfolio_service/backtest_portfolio_service.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/position_snapshot_service.py +0 -0
- {investing_algorithm_framework-2.3.2 → investing_algorithm_framework-2.5.0}/investing_algorithm_framework/services/repository_service.py +0 -0
|
@@ -1,40 +1,29 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
|
-
Name:
|
|
3
|
-
Version: 2.
|
|
4
|
-
Summary: A framework for creating
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Author: coding kitties
|
|
8
|
-
License: Apache License 2.0
|
|
9
|
-
Keywords: TRADING,INVESTING,BOT,ALGORITHM,FRAMEWORK
|
|
10
|
-
Classifier: Intended Audience :: Developers
|
|
2
|
+
Name: investing-algorithm-framework
|
|
3
|
+
Version: 2.5.0
|
|
4
|
+
Summary: A framework for creating trading bots
|
|
5
|
+
Author: MDUYN
|
|
6
|
+
Requires-Python: >=3.8.1,<4.0.0
|
|
11
7
|
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.
|
|
15
|
-
Classifier:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Requires-
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Requires-Dist: Flask (>=2.3.2,<3.0.0)
|
|
13
|
+
Requires-Dist: Flask-Cors (>=3.0.9,<4.0.0)
|
|
14
|
+
Requires-Dist: Flask-Migrate (>=2.6.0,<3.0.0)
|
|
15
|
+
Requires-Dist: MarkupSafe (>=2.1.2,<3.0.0)
|
|
16
|
+
Requires-Dist: SQLAlchemy (>=2.0.18,<3.0.0)
|
|
17
|
+
Requires-Dist: ccxt (>=4.2.48,<5.0.0)
|
|
18
|
+
Requires-Dist: dependency-injector (>=4.40.0,<5.0.0)
|
|
19
|
+
Requires-Dist: marshmallow (>=3.5.0,<4.0.0)
|
|
20
|
+
Requires-Dist: polars[numpy,pandas] (>=0.20.10,<0.21.0)
|
|
21
|
+
Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
|
|
22
|
+
Requires-Dist: schedule (>=1.1.0,<2.0.0)
|
|
23
|
+
Requires-Dist: tabulate (>=0.9.0,<0.10.0)
|
|
24
|
+
Requires-Dist: tqdm (>=4.66.1,<5.0.0)
|
|
25
|
+
Requires-Dist: wrapt (>=1.16.0,<2.0.0)
|
|
19
26
|
Description-Content-Type: text/markdown
|
|
20
|
-
License-File: LICENSE
|
|
21
|
-
License-File: AUTHORS.md
|
|
22
|
-
Requires-Dist: wrapt>=1.11.2
|
|
23
|
-
Requires-Dist: Flask>=2.3.2
|
|
24
|
-
Requires-Dist: Flask-Migrate>=2.6.0
|
|
25
|
-
Requires-Dist: Flask-Cors>=3.0.9
|
|
26
|
-
Requires-Dist: SQLAlchemy>=2.0.18
|
|
27
|
-
Requires-Dist: marshmallow>=3.5.0
|
|
28
|
-
Requires-Dist: setuptools>=60.9.0
|
|
29
|
-
Requires-Dist: ccxt>=3.0.57
|
|
30
|
-
Requires-Dist: python-dateutil>=2.8.2
|
|
31
|
-
Requires-Dist: MarkupSafe>=2.1.2
|
|
32
|
-
Requires-Dist: dependency-injector>=4.40.0
|
|
33
|
-
Requires-Dist: schedule>=1.1.0
|
|
34
|
-
Requires-Dist: pandas>=2.0.0
|
|
35
|
-
Requires-Dist: tqdm>=4.66.1
|
|
36
|
-
Requires-Dist: tabulate>=0.9.0
|
|
37
|
-
Requires-Dist: polars[numpy,pandas]==0.20.5
|
|
38
27
|
|
|
39
28
|
<a href=https://investing-algorithm-framework.com><img src="https://img.shields.io/badge/docs-website-brightgreen"></a>
|
|
40
29
|
[](https://github.com/coding-kitties/investing-algorithm-framework/actions/workflows/build.yml)
|
|
@@ -47,7 +36,7 @@ Requires-Dist: polars[numpy,pandas]==0.20.5
|
|
|
47
36
|
###### Sponsors
|
|
48
37
|
<p align="left">
|
|
49
38
|
<a href="https://finterion.com">
|
|
50
|
-
<img alt="Finterion" src="
|
|
39
|
+
<img alt="Finterion" src="static/sponsors/finterion.png" width="200px" />
|
|
51
40
|
</a>
|
|
52
41
|
</p>
|
|
53
42
|
|
|
@@ -351,3 +340,4 @@ You can pick up a task by assigning yourself to it.
|
|
|
351
340
|
This will ensure that interested parties can give valuable feedback on the feature, and let others know that you are working on it.
|
|
352
341
|
|
|
353
342
|
**Important:** Always create your feature or hotfix against the `develop` branch, not `master`.
|
|
343
|
+
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
###### Sponsors
|
|
10
10
|
<p align="left">
|
|
11
11
|
<a href="https://finterion.com">
|
|
12
|
-
<img alt="Finterion" src="
|
|
12
|
+
<img alt="Finterion" src="static/sponsors/finterion.png" width="200px" />
|
|
13
13
|
</a>
|
|
14
14
|
</p>
|
|
15
15
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from investing_algorithm_framework.app import App, Algorithm
|
|
2
2
|
from .create_app import create_app
|
|
3
3
|
from investing_algorithm_framework.domain import ApiException, \
|
|
4
|
-
TradingDataType, TradingTimeFrame, OrderType
|
|
4
|
+
TradingDataType, TradingTimeFrame, OrderType, \
|
|
5
5
|
OrderStatus, OrderSide, Config, TimeUnit, TimeInterval, Order, Portfolio, \
|
|
6
6
|
Position, TimeFrame, BACKTESTING_INDEX_DATETIME, MarketCredential, \
|
|
7
7
|
PortfolioConfiguration, RESOURCE_DIRECTORY, pretty_print_backtest, \
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import logging
|
|
2
1
|
import decimal
|
|
2
|
+
import logging
|
|
3
3
|
from typing import List
|
|
4
4
|
|
|
5
5
|
from investing_algorithm_framework.domain import OrderStatus, OrderFee, \
|
|
6
6
|
Position, Order, Portfolio, OrderType, OrderSide, ApiException, \
|
|
7
|
-
BACKTESTING_FLAG, BACKTESTING_INDEX_DATETIME,
|
|
8
|
-
MarketService
|
|
7
|
+
BACKTESTING_FLAG, BACKTESTING_INDEX_DATETIME, MarketService
|
|
9
8
|
from investing_algorithm_framework.services import MarketCredentialService, \
|
|
10
|
-
MarketDataSourceService
|
|
9
|
+
MarketDataSourceService, PortfolioService, PositionService, TradeService, \
|
|
10
|
+
OrderService, ConfigurationService, StrategyOrchestratorService, \
|
|
11
|
+
PortfolioConfigurationService
|
|
11
12
|
|
|
12
13
|
logger = logging.getLogger("investing_algorithm_framework")
|
|
13
14
|
|
|
@@ -24,21 +25,26 @@ class Algorithm:
|
|
|
24
25
|
market_service,
|
|
25
26
|
strategy_orchestrator_service,
|
|
26
27
|
market_credential_service,
|
|
27
|
-
market_data_source_service
|
|
28
|
+
market_data_source_service,
|
|
29
|
+
trade_service
|
|
28
30
|
):
|
|
29
|
-
self.portfolio_service = portfolio_service
|
|
30
|
-
self.position_service = position_service
|
|
31
|
-
self.order_service = order_service
|
|
32
|
-
self.
|
|
33
|
-
self.configuration_service
|
|
34
|
-
|
|
35
|
-
self.
|
|
31
|
+
self.portfolio_service: PortfolioService = portfolio_service
|
|
32
|
+
self.position_service: PositionService = position_service
|
|
33
|
+
self.order_service: OrderService = order_service
|
|
34
|
+
self.market_service: MarketService = market_service
|
|
35
|
+
self.configuration_service: ConfigurationService \
|
|
36
|
+
= configuration_service
|
|
37
|
+
self.portfolio_configuration_service: PortfolioConfigurationService \
|
|
38
|
+
= portfolio_configuration_service
|
|
39
|
+
self.strategy_orchestrator_service: StrategyOrchestratorService \
|
|
40
|
+
= strategy_orchestrator_service
|
|
36
41
|
self._market_data_sources = {}
|
|
37
42
|
self._strategies = []
|
|
38
43
|
self._market_credential_service: MarketCredentialService \
|
|
39
44
|
= market_credential_service
|
|
40
45
|
self._market_data_source_service: MarketDataSourceService \
|
|
41
46
|
= market_data_source_service
|
|
47
|
+
self.trade_service: TradeService = trade_service
|
|
42
48
|
|
|
43
49
|
def start(self, number_of_iterations=None, stateless=False):
|
|
44
50
|
|
|
@@ -158,14 +164,14 @@ class Algorithm:
|
|
|
158
164
|
)
|
|
159
165
|
|
|
160
166
|
def create_market_order(
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
self,
|
|
168
|
+
target_symbol,
|
|
169
|
+
order_side,
|
|
170
|
+
amount,
|
|
171
|
+
market=None,
|
|
172
|
+
execute=False,
|
|
173
|
+
validate=False,
|
|
174
|
+
sync=True
|
|
169
175
|
):
|
|
170
176
|
|
|
171
177
|
if market is None:
|
|
@@ -210,18 +216,24 @@ class Algorithm:
|
|
|
210
216
|
{"portfolio": portfolio.id, "symbol": trading_symbol}
|
|
211
217
|
).get_amount()
|
|
212
218
|
|
|
219
|
+
def get_total_size(self):
|
|
220
|
+
"""
|
|
221
|
+
Returns the total size of the portfolio.
|
|
222
|
+
"""
|
|
223
|
+
return self.get_unallocated() + self.get_allocated()
|
|
224
|
+
|
|
213
225
|
def reset(self):
|
|
214
226
|
self._workers = []
|
|
215
227
|
self._running_workers = []
|
|
216
228
|
|
|
217
229
|
def get_order(
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
230
|
+
self,
|
|
231
|
+
reference_id=None,
|
|
232
|
+
market=None,
|
|
233
|
+
target_symbol=None,
|
|
234
|
+
trading_symbol=None,
|
|
235
|
+
order_side=None,
|
|
236
|
+
order_type=None
|
|
225
237
|
) -> Order:
|
|
226
238
|
query_params = {}
|
|
227
239
|
|
|
@@ -250,12 +262,12 @@ class Algorithm:
|
|
|
250
262
|
return self.order_service.find(query_params)
|
|
251
263
|
|
|
252
264
|
def get_orders(
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
265
|
+
self,
|
|
266
|
+
target_symbol=None,
|
|
267
|
+
status=None,
|
|
268
|
+
order_type=None,
|
|
269
|
+
order_side=None,
|
|
270
|
+
market=None
|
|
259
271
|
) -> List[Order]:
|
|
260
272
|
|
|
261
273
|
if market is None:
|
|
@@ -278,13 +290,13 @@ class Algorithm:
|
|
|
278
290
|
return self.order_service.get_order_fee(order_id)
|
|
279
291
|
|
|
280
292
|
def get_positions(
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
293
|
+
self,
|
|
294
|
+
market=None,
|
|
295
|
+
identifier=None,
|
|
296
|
+
amount_gt=None,
|
|
297
|
+
amount_gte=None,
|
|
298
|
+
amount_lt=None,
|
|
299
|
+
amount_lte=None
|
|
288
300
|
) -> List[Position]:
|
|
289
301
|
query_params = {}
|
|
290
302
|
|
|
@@ -340,14 +352,14 @@ class Algorithm:
|
|
|
340
352
|
return None
|
|
341
353
|
|
|
342
354
|
def has_position(
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
355
|
+
self,
|
|
356
|
+
symbol,
|
|
357
|
+
market=None,
|
|
358
|
+
identifier=None,
|
|
359
|
+
amount_gt=0,
|
|
360
|
+
amount_gte=None,
|
|
361
|
+
amount_lt=None,
|
|
362
|
+
amount_lte=None
|
|
351
363
|
):
|
|
352
364
|
return self.position_exists(
|
|
353
365
|
symbol,
|
|
@@ -592,9 +604,9 @@ class Algorithm:
|
|
|
592
604
|
orders = self.order_service.get_all(
|
|
593
605
|
{"status": OrderStatus.OPEN.value, "portfolio": portfolio.id}
|
|
594
606
|
)
|
|
595
|
-
unfilled = unfilled
|
|
596
|
-
|
|
597
|
-
|
|
607
|
+
unfilled = unfilled + sum(
|
|
608
|
+
[order.get_amount() * order.get_price() for order in orders]
|
|
609
|
+
)
|
|
598
610
|
|
|
599
611
|
return unfilled
|
|
600
612
|
|
|
@@ -642,7 +654,9 @@ class Algorithm:
|
|
|
642
654
|
query_params["status"] = OrderStatus.OPEN.value
|
|
643
655
|
return self.order_service.exists(query_params)
|
|
644
656
|
|
|
645
|
-
def has_open_orders(
|
|
657
|
+
def has_open_orders(
|
|
658
|
+
self, target_symbol=None, identifier=None, market=None
|
|
659
|
+
):
|
|
646
660
|
query_params = {}
|
|
647
661
|
|
|
648
662
|
if identifier is not None:
|
|
@@ -667,55 +681,10 @@ class Algorithm:
|
|
|
667
681
|
self.order_service.check_pending_orders()
|
|
668
682
|
|
|
669
683
|
def get_trades(self, market=None):
|
|
670
|
-
|
|
671
|
-
trades = []
|
|
672
|
-
|
|
673
|
-
for portfolio in portfolios:
|
|
674
|
-
buy_orders = self.order_service.get_all({
|
|
675
|
-
"status": OrderStatus.CLOSED.value,
|
|
676
|
-
"order_side": OrderSide.BUY.value,
|
|
677
|
-
"portfolio_id": portfolio.id
|
|
678
|
-
})
|
|
679
|
-
|
|
680
|
-
for buy_order in buy_orders:
|
|
681
|
-
symbol = buy_order.get_symbol()
|
|
682
|
-
ticker = self._market_data_source_service.get_ticker(
|
|
683
|
-
symbol=symbol, market=market
|
|
684
|
-
)
|
|
685
|
-
trades.append(
|
|
686
|
-
Trade(
|
|
687
|
-
buy_order_id=buy_order.id,
|
|
688
|
-
target_symbol=buy_order.get_target_symbol(),
|
|
689
|
-
trading_symbol=buy_order.get_trading_symbol(),
|
|
690
|
-
amount=buy_order.get_amount(),
|
|
691
|
-
open_price=buy_order.get_price(),
|
|
692
|
-
closed_price=buy_order.get_trade_closed_price(),
|
|
693
|
-
closed_at=buy_order.get_trade_closed_at(),
|
|
694
|
-
opened_at=buy_order.get_created_at(),
|
|
695
|
-
current_price=ticker["bid"]
|
|
696
|
-
)
|
|
697
|
-
)
|
|
698
|
-
|
|
699
|
-
return trades
|
|
684
|
+
return self.trade_service.get_trades(market)
|
|
700
685
|
|
|
701
686
|
def get_closed_trades(self):
|
|
702
|
-
|
|
703
|
-
"status": OrderStatus.CLOSED.value,
|
|
704
|
-
"order_side": OrderSide.BUY.value
|
|
705
|
-
})
|
|
706
|
-
return [
|
|
707
|
-
Trade(
|
|
708
|
-
buy_order_id=order.id,
|
|
709
|
-
target_symbol=order.get_target_symbol(),
|
|
710
|
-
trading_symbol=order.get_trading_symbol(),
|
|
711
|
-
amount=order.get_amount(),
|
|
712
|
-
open_price=order.get_price(),
|
|
713
|
-
closed_price=order.get_trade_closed_price(),
|
|
714
|
-
closed_at=order.get_trade_closed_at(),
|
|
715
|
-
opened_at=order.get_created_at()
|
|
716
|
-
) for order in buy_orders
|
|
717
|
-
if order.get_trade_closed_at() is not None
|
|
718
|
-
]
|
|
687
|
+
return self.trade_service.get_closed_trades()
|
|
719
688
|
|
|
720
689
|
def round_down(self, value, amount_of_decimals):
|
|
721
690
|
|
|
@@ -735,132 +704,10 @@ class Algorithm:
|
|
|
735
704
|
return 0
|
|
736
705
|
|
|
737
706
|
def get_open_trades(self, target_symbol=None, market=None):
|
|
738
|
-
|
|
739
|
-
trades = []
|
|
740
|
-
|
|
741
|
-
for portfolio in portfolios:
|
|
742
|
-
|
|
743
|
-
if target_symbol is not None:
|
|
744
|
-
buy_orders = self.order_service.get_all({
|
|
745
|
-
"status": OrderStatus.CLOSED.value,
|
|
746
|
-
"order_side": OrderSide.BUY.value,
|
|
747
|
-
"portfolio_id": portfolio.id,
|
|
748
|
-
"target_symbol": target_symbol
|
|
749
|
-
})
|
|
750
|
-
sell_orders = self.order_service.get_all({
|
|
751
|
-
"status": OrderStatus.OPEN.value,
|
|
752
|
-
"order_side": OrderSide.SELL.value,
|
|
753
|
-
"portfolio_id": portfolio.id,
|
|
754
|
-
"target_symbol": target_symbol
|
|
755
|
-
})
|
|
756
|
-
else:
|
|
757
|
-
buy_orders = self.order_service.get_all({
|
|
758
|
-
"status": OrderStatus.CLOSED.value,
|
|
759
|
-
"order_side": OrderSide.BUY.value,
|
|
760
|
-
"portfolio_id": portfolio.id
|
|
761
|
-
})
|
|
762
|
-
sell_orders = self.order_service.get_all({
|
|
763
|
-
"status": OrderStatus.OPEN.value,
|
|
764
|
-
"order_side": OrderSide.SELL.value,
|
|
765
|
-
"portfolio_id": portfolio.id
|
|
766
|
-
})
|
|
767
|
-
|
|
768
|
-
buy_orders = [
|
|
769
|
-
buy_order for buy_order in buy_orders
|
|
770
|
-
if buy_order.get_trade_closed_at() is None
|
|
771
|
-
]
|
|
772
|
-
sell_amount = sum([order.amount for order in sell_orders])
|
|
773
|
-
|
|
774
|
-
# Subtract the amount of the open sell orders
|
|
775
|
-
# from the amount of the buy orders
|
|
776
|
-
buy_orders_queue = PeekableQueue()
|
|
777
|
-
|
|
778
|
-
for buy_order in buy_orders:
|
|
779
|
-
buy_orders_queue.enqueue(buy_order)
|
|
780
|
-
|
|
781
|
-
while sell_amount > 0 and not buy_orders_queue.is_empty():
|
|
782
|
-
first_buy_order = buy_orders_queue.peek()
|
|
783
|
-
available = first_buy_order.get_filled() \
|
|
784
|
-
- first_buy_order.get_trade_closed_amount()
|
|
785
|
-
|
|
786
|
-
if available > sell_amount:
|
|
787
|
-
remaining = available - sell_amount
|
|
788
|
-
sell_amount = 0
|
|
789
|
-
first_buy_order.set_filled(remaining)
|
|
790
|
-
else:
|
|
791
|
-
sell_amount = sell_amount - available
|
|
792
|
-
buy_orders_queue.dequeue()
|
|
793
|
-
|
|
794
|
-
for buy_order in buy_orders_queue:
|
|
795
|
-
symbol = buy_order.get_symbol()
|
|
796
|
-
|
|
797
|
-
try:
|
|
798
|
-
ticker = self._market_data_source_service.get_ticker(
|
|
799
|
-
symbol=symbol, market=market
|
|
800
|
-
)
|
|
801
|
-
except Exception as e:
|
|
802
|
-
logger.error(e)
|
|
803
|
-
raise ApiException(
|
|
804
|
-
f"Error getting ticker data for "
|
|
805
|
-
f"trade {buy_order.get_target_symbol()}"
|
|
806
|
-
f"-{buy_order.get_trading_symbol()}. Make sure you "
|
|
807
|
-
f"have registered a ticker market data source for "
|
|
808
|
-
f"{buy_order.get_target_symbol()}"
|
|
809
|
-
f"-{buy_order.get_trading_symbol()} "
|
|
810
|
-
f"for market {portfolio.market}"
|
|
811
|
-
)
|
|
812
|
-
trades.append(
|
|
813
|
-
Trade(
|
|
814
|
-
buy_order_id=buy_order.id,
|
|
815
|
-
target_symbol=buy_order.get_target_symbol(),
|
|
816
|
-
trading_symbol=buy_order.get_trading_symbol(),
|
|
817
|
-
amount=buy_order.get_filled()
|
|
818
|
-
- buy_order.get_trade_closed_amount(),
|
|
819
|
-
open_price=buy_order.get_price(),
|
|
820
|
-
opened_at=buy_order.get_created_at(),
|
|
821
|
-
current_price=ticker["bid"]
|
|
822
|
-
)
|
|
823
|
-
)
|
|
824
|
-
|
|
825
|
-
return trades
|
|
707
|
+
return self.trade_service.get_open_trades(target_symbol, market)
|
|
826
708
|
|
|
827
709
|
def close_trade(self, trade, market=None):
|
|
828
|
-
|
|
829
|
-
if trade.closed_at is not None:
|
|
830
|
-
raise ApiException("Trade already closed.")
|
|
831
|
-
|
|
832
|
-
order = self.order_service.get(trade.buy_order_id)
|
|
833
|
-
|
|
834
|
-
if order.get_filled() <= 0:
|
|
835
|
-
raise ApiException(
|
|
836
|
-
"Buy order belonging to the trade has no amount."
|
|
837
|
-
)
|
|
838
|
-
|
|
839
|
-
portfolio = self.portfolio_service\
|
|
840
|
-
.find({"position": order.position_id})
|
|
841
|
-
position = self.get_position(order.get_target_symbol())
|
|
842
|
-
amount = order.get_amount()
|
|
843
|
-
|
|
844
|
-
if position.get_amount() < amount:
|
|
845
|
-
logger.warning(
|
|
846
|
-
f"Order amount {amount} is larger then amount "
|
|
847
|
-
f"of available {position.symbol} "
|
|
848
|
-
f"position: {position.get_amount()}, "
|
|
849
|
-
f"changing order amount to size of position"
|
|
850
|
-
)
|
|
851
|
-
amount = position.get_amount()
|
|
852
|
-
|
|
853
|
-
symbol = f"{order.get_target_symbol().upper()}" \
|
|
854
|
-
f"/{order.get_trading_symbol().upper()}"
|
|
855
|
-
ticker = self._market_data_source_service.get_ticker(
|
|
856
|
-
symbol=symbol, market=market
|
|
857
|
-
)
|
|
858
|
-
self.create_limit_order(
|
|
859
|
-
target_symbol=order.target_symbol,
|
|
860
|
-
amount=amount,
|
|
861
|
-
order_side=OrderSide.SELL.value,
|
|
862
|
-
price=ticker["bid"],
|
|
863
|
-
)
|
|
710
|
+
self.trade_service.close_trade(trade, market)
|
|
864
711
|
|
|
865
712
|
def get_number_of_positions(self):
|
|
866
713
|
"""
|
|
@@ -17,7 +17,7 @@ from investing_algorithm_framework.app.web import create_flask_app
|
|
|
17
17
|
from investing_algorithm_framework.domain import DATABASE_NAME, TimeUnit, \
|
|
18
18
|
DATABASE_DIRECTORY_PATH, RESOURCE_DIRECTORY, ENVIRONMENT, Environment, \
|
|
19
19
|
SQLALCHEMY_DATABASE_URI, OperationalException, BACKTESTING_FLAG, \
|
|
20
|
-
BACKTESTING_START_DATE,
|
|
20
|
+
BACKTESTING_START_DATE, BACKTESTING_END_DATE, \
|
|
21
21
|
BACKTESTING_PENDING_ORDER_CHECK_INTERVAL
|
|
22
22
|
from investing_algorithm_framework.infrastructure import setup_sqlalchemy, \
|
|
23
23
|
create_all_tables
|
|
@@ -40,7 +40,6 @@ class App:
|
|
|
40
40
|
self._strategies = []
|
|
41
41
|
self._tasks = []
|
|
42
42
|
self._configuration_service = None
|
|
43
|
-
self._market_service: MarketService = None
|
|
44
43
|
self._market_data_source_service: MarketDataSourceService = None
|
|
45
44
|
self._market_credential_service: MarketCredentialService = None
|
|
46
45
|
|
|
@@ -50,13 +49,19 @@ class App:
|
|
|
50
49
|
|
|
51
50
|
def initialize_services(self):
|
|
52
51
|
self._configuration_service = self.container.configuration_service()
|
|
53
|
-
self._market_service = self.container.market_service()
|
|
54
52
|
self._market_data_source_service = \
|
|
55
53
|
self.container.market_data_source_service()
|
|
56
54
|
self._market_credential_service = \
|
|
57
55
|
self.container.market_credential_service()
|
|
58
56
|
|
|
59
57
|
def initialize(self):
|
|
58
|
+
"""
|
|
59
|
+
Method to initialize the app. This method should be called before
|
|
60
|
+
running the algorithm. It initializes the services and the algorithm
|
|
61
|
+
and sets up the database if it does not exist.
|
|
62
|
+
|
|
63
|
+
:return: None
|
|
64
|
+
"""
|
|
60
65
|
|
|
61
66
|
if self._web:
|
|
62
67
|
self._initialize_web()
|
|
@@ -70,13 +75,21 @@ class App:
|
|
|
70
75
|
self._initialize_standard()
|
|
71
76
|
setup_sqlalchemy(self)
|
|
72
77
|
create_all_tables()
|
|
78
|
+
|
|
79
|
+
# Initialize the algorithm
|
|
73
80
|
self.algorithm = self.container.algorithm()
|
|
81
|
+
|
|
82
|
+
# Add strategies
|
|
74
83
|
self.algorithm.add_strategies(self.strategies)
|
|
84
|
+
|
|
85
|
+
# Add tasks
|
|
75
86
|
self.algorithm.add_tasks(self.tasks)
|
|
76
87
|
|
|
88
|
+
# Initialize all portfolios that are registered
|
|
77
89
|
portfolio_configuration_service = self.container\
|
|
78
90
|
.portfolio_configuration_service()
|
|
79
91
|
|
|
92
|
+
# Throw an error if no portfolios are configured
|
|
80
93
|
if portfolio_configuration_service.count() == 0:
|
|
81
94
|
raise OperationalException("No portfolios configured")
|
|
82
95
|
|
|
@@ -85,15 +98,42 @@ class App:
|
|
|
85
98
|
portfolio_service = self.container.portfolio_service()
|
|
86
99
|
|
|
87
100
|
for portfolio_configuration in portfolio_configurations:
|
|
88
|
-
|
|
101
|
+
# Create portfolio if not exists
|
|
102
|
+
portfolio = portfolio_service.create_portfolio_from_configuration(
|
|
89
103
|
portfolio_configuration
|
|
90
104
|
)
|
|
105
|
+
# Sync all orders from exchange with current order history
|
|
106
|
+
portfolio_service.sync_portfolio_orders(portfolio)
|
|
91
107
|
|
|
92
108
|
def _initialize_stateless(self):
|
|
109
|
+
"""
|
|
110
|
+
Initialize the app for stateless mode by setting the configuration
|
|
111
|
+
parameters for stateless mode and overriding the services with the
|
|
112
|
+
stateless services equivalents.
|
|
113
|
+
|
|
114
|
+
In stateless mode, sqlalchemy is-setup with an in-memory database.
|
|
115
|
+
|
|
116
|
+
Stateless has the following implications:
|
|
117
|
+
db: in-memory
|
|
118
|
+
web: False
|
|
119
|
+
app: Run with stateless action objects
|
|
120
|
+
algorithm: Run with stateless action objects
|
|
121
|
+
"""
|
|
93
122
|
configuration_service = self.container.configuration_service()
|
|
94
123
|
configuration_service.config[SQLALCHEMY_DATABASE_URI] = "sqlite://"
|
|
95
124
|
|
|
96
125
|
def _initialize_standard(self):
|
|
126
|
+
"""
|
|
127
|
+
Initialize the app for standard mode by setting the configuration
|
|
128
|
+
parameters for standard mode and overriding the services with the
|
|
129
|
+
standard services equivalents.
|
|
130
|
+
|
|
131
|
+
Standard has the following implications:
|
|
132
|
+
db: sqlite
|
|
133
|
+
web: False
|
|
134
|
+
app: Standard
|
|
135
|
+
algorithm: Standard
|
|
136
|
+
"""
|
|
97
137
|
configuration_service = self.container.configuration_service()
|
|
98
138
|
resource_dir = configuration_service.config[RESOURCE_DIRECTORY]
|
|
99
139
|
|
|
@@ -197,6 +237,9 @@ class App:
|
|
|
197
237
|
portfolio_snapshot_service=self.container
|
|
198
238
|
.portfolio_snapshot_service(),
|
|
199
239
|
))
|
|
240
|
+
market_data_source_service = \
|
|
241
|
+
self.container.market_data_source_service()
|
|
242
|
+
|
|
200
243
|
# Override the order service with the backtest order service
|
|
201
244
|
self.container.order_service.override(
|
|
202
245
|
OrderBacktestService(
|
|
@@ -209,7 +252,7 @@ class App:
|
|
|
209
252
|
portfolio_snapshot_service=self.container
|
|
210
253
|
.portfolio_snapshot_service(),
|
|
211
254
|
configuration_service=self.container.configuration_service(),
|
|
212
|
-
market_data_source_service=
|
|
255
|
+
market_data_source_service=market_data_source_service
|
|
213
256
|
)
|
|
214
257
|
)
|
|
215
258
|
|
|
@@ -256,14 +299,8 @@ class App:
|
|
|
256
299
|
self,
|
|
257
300
|
payload: dict = None,
|
|
258
301
|
number_of_iterations: int = None,
|
|
259
|
-
sync=True
|
|
260
302
|
):
|
|
261
303
|
self.initialize()
|
|
262
|
-
portfolio_service = self.container.portfolio_service()
|
|
263
|
-
|
|
264
|
-
if sync:
|
|
265
|
-
portfolio_service.sync_portfolios()
|
|
266
|
-
|
|
267
304
|
self.algorithm.start(
|
|
268
305
|
number_of_iterations=number_of_iterations,
|
|
269
306
|
stateless=self.stateless
|
|
@@ -438,13 +475,6 @@ class App:
|
|
|
438
475
|
def tasks(self):
|
|
439
476
|
return self._tasks
|
|
440
477
|
|
|
441
|
-
def sync_portfolios(self):
|
|
442
|
-
portfolio_configuration_service = self.container\
|
|
443
|
-
.portfolio_configuration_service()
|
|
444
|
-
portfolio_configuration_service.create_portfolios()
|
|
445
|
-
portfolio_service = self.container.portfolio_service()
|
|
446
|
-
portfolio_service.sync_portfolios()
|
|
447
|
-
|
|
448
478
|
def _initialize_web(self):
|
|
449
479
|
configuration_service = self.container.configuration_service()
|
|
450
480
|
resource_dir = configuration_service.config[RESOURCE_DIRECTORY]
|
|
@@ -453,9 +483,8 @@ class App:
|
|
|
453
483
|
configuration_service.config[SQLALCHEMY_DATABASE_URI] = "sqlite://"
|
|
454
484
|
else:
|
|
455
485
|
resource_dir = self._create_resource_directory_if_not_exists()
|
|
456
|
-
configuration_service.config[DATABASE_DIRECTORY_PATH] =
|
|
457
|
-
resource_dir, "databases"
|
|
458
|
-
)
|
|
486
|
+
configuration_service.config[DATABASE_DIRECTORY_PATH] = \
|
|
487
|
+
os.path.join(resource_dir, "databases")
|
|
459
488
|
configuration_service.config[DATABASE_NAME] \
|
|
460
489
|
= "prod-database.sqlite3"
|
|
461
490
|
configuration_service.config[SQLALCHEMY_DATABASE_URI] = \
|
|
@@ -528,7 +557,11 @@ class App:
|
|
|
528
557
|
return self.algorithm.get_portfolio_configurations()
|
|
529
558
|
|
|
530
559
|
def backtest(
|
|
531
|
-
self,
|
|
560
|
+
self,
|
|
561
|
+
start_date,
|
|
562
|
+
end_date,
|
|
563
|
+
pending_order_check_interval='1h',
|
|
564
|
+
output_directory=None
|
|
532
565
|
):
|
|
533
566
|
logger.info("Initializing backtest")
|
|
534
567
|
|
|
@@ -547,6 +580,19 @@ class App:
|
|
|
547
580
|
report = backtest_service.backtest(
|
|
548
581
|
self.algorithm, start_date, end_date
|
|
549
582
|
)
|
|
583
|
+
backtest_report_writer_service = self.container\
|
|
584
|
+
.backtest_report_writer_service()
|
|
585
|
+
|
|
586
|
+
if output_directory is None:
|
|
587
|
+
output_directory = os.path.join(
|
|
588
|
+
self.config.get(RESOURCE_DIRECTORY),
|
|
589
|
+
"backtest_reports"
|
|
590
|
+
)
|
|
591
|
+
|
|
592
|
+
backtest_report_writer_service.write_report_to_csv(
|
|
593
|
+
report=report, output_directory=output_directory
|
|
594
|
+
)
|
|
595
|
+
|
|
550
596
|
return report
|
|
551
597
|
|
|
552
598
|
def add_market_data_source(self, market_data_source):
|