investing-algorithm-framework 3.2.0__tar.gz → 3.3.1__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-3.2.0 → investing_algorithm_framework-3.3.1}/PKG-INFO +16 -16
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/README.md +15 -15
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/app.py +7 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/dependency_container.py +2 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/config.py +1 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/order/order.py +1 -5
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/trade/trade.py +44 -9
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/services/market_data_sources.py +21 -7
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py +36 -15
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +46 -53
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py +26 -12
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/backtesting/backtest_service.py +5 -2
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py +1 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/order_service/order_backtest_service.py +0 -3
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/order_service/order_service.py +2 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/trade_service/trade_service.py +13 -15
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/pyproject.toml +1 -1
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/LICENSE +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/algorithm.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/stateless/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/stateless/action_handlers/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/stateless/exception_handler.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/strategy.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/task.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/web/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/web/controllers/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/web/controllers/orders.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/web/controllers/portfolio.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/web/controllers/positions.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/web/create_app.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/web/error_handler.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/web/responses.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/web/run_strategies.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/web/schemas/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/web/schemas/order.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/web/schemas/portfolio.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/web/schemas/position.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/app/web/setup_cors.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/create_app.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/constants.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/data_structures.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/decimal_parsing.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/exceptions.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/app_mode.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/backtesting/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/backtesting/backtest_position.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/backtesting/backtest_report.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/base_model.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/market/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/market/market_credential.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/order/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/order/order_fee.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/order/order_side.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/order/order_status.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/order/order_type.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/portfolio/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/portfolio/portfolio.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/position/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/position/position.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/position/position_snapshot.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/strategy_profile.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/time_frame.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/time_interval.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/time_unit.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/trade/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/trade/trade_status.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/trading_data_types.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/models/trading_time_frame.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/services/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/services/market_credential_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/services/market_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/services/portfolios/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/services/portfolios/portfolio_sync_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/singleton.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/stateless_actions.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/strategy.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/utils/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/utils/backtesting.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/utils/csv.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/utils/random.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/utils/signatures.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/utils/stoppable_thread.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/domain/utils/synchronized.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/database/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/database/sql_alchemy.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/models/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/models/decimal_parser.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/models/market_data_sources/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/models/model_extension.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/models/order/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/models/order/order.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/models/order/order_fee.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/models/portfolio/portfolio.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/models/position/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/models/position/position.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/models/position/position_snapshot.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/repositories/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/repositories/order_fee_repository.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/repositories/order_repository.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/repositories/portfolio_snapshot_repository.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/repositories/position_repository.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/repositories/position_snapshot_repository.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/repositories/repository.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/services/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/services/market_service/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/services/performance_service/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/services/performance_service/backtest_performance_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/infrastructure/services/performance_service/performance_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/backtesting/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/backtesting/backtest_report_writer_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/configuration_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/market_credential_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/market_data_source_service/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/order_service/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/portfolios/__init__.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/portfolios/backtest_portfolio_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/portfolios/portfolio_configuration_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/portfolios/portfolio_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/position_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/position_snapshot_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/repository_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -0
- {investing_algorithm_framework-3.2.0 → investing_algorithm_framework-3.3.1}/investing_algorithm_framework/services/trade_service/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: investing-algorithm-framework
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.3.1
|
|
4
4
|
Summary: A framework for creating trading bots
|
|
5
5
|
Author: MDUYN
|
|
6
6
|
Requires-Python: >=3.8.1,<4.0.0
|
|
@@ -174,20 +174,20 @@ you will get the following backtesting report:
|
|
|
174
174
|
====================Portfolio overview============================
|
|
175
175
|
* Number of orders: 10
|
|
176
176
|
* Initial balance: 400.0000 EUR
|
|
177
|
-
* Final balance:
|
|
178
|
-
* Total net gain:
|
|
179
|
-
* Total net gain percentage:
|
|
180
|
-
* Growth rate:
|
|
181
|
-
* Growth
|
|
177
|
+
* Final balance: 431.8837 EUR
|
|
178
|
+
* Total net gain: 28.4171 EUR
|
|
179
|
+
* Total net gain percentage: 7.1043%
|
|
180
|
+
* Growth rate: 7.9709%
|
|
181
|
+
* Growth 31.8837 EUR
|
|
182
182
|
====================Positions overview========================
|
|
183
183
|
╭────────────┬──────────┬──────────────────────┬───────────────────────┬──────────────┬───────────────┬───────────────────────────┬────────────────┬───────────────╮
|
|
184
184
|
│ Position │ Amount │ Pending buy amount │ Pending sell amount │ Cost (EUR) │ Value (EUR) │ Percentage of portfolio │ Growth (EUR) │ Growth_rate │
|
|
185
185
|
├────────────┼──────────┼──────────────────────┼───────────────────────┼──────────────┼───────────────┼───────────────────────────┼────────────────┼───────────────┤
|
|
186
|
-
│ EUR │
|
|
186
|
+
│ EUR │ 214.219 │ 0 │ 0 │ 214.219 │ 214.219 │ 49.6010% │ 0 │ 0.0000% │
|
|
187
187
|
├────────────┼──────────┼──────────────────────┼───────────────────────┼──────────────┼───────────────┼───────────────────────────┼────────────────┼───────────────┤
|
|
188
|
-
│ BTC │ 0.
|
|
188
|
+
│ BTC │ 0.0031 │ 0 │ 0 │ 107.095 │ 110.401 │ 25.5627% │ 3.3066 │ 3.0875% │
|
|
189
189
|
├────────────┼──────────┼──────────────────────┼───────────────────────┼──────────────┼───────────────┼───────────────────────────┼────────────────┼───────────────┤
|
|
190
|
-
│ DOT │ 21.
|
|
190
|
+
│ DOT │ 21.3291 │ 0 │ 0 │ 107.104 │ 107.264 │ 24.8363% │ 0.16 │ 0.1494% │
|
|
191
191
|
╰────────────┴──────────┴──────────────────────┴───────────────────────┴──────────────┴───────────────┴───────────────────────────┴────────────────┴───────────────╯
|
|
192
192
|
====================Trades overview===========================
|
|
193
193
|
* Number of trades closed: 4
|
|
@@ -195,21 +195,21 @@ you will get the following backtesting report:
|
|
|
195
195
|
* Percentage of positive trades: 60.0%
|
|
196
196
|
* Percentage of negative trades: 20.0%
|
|
197
197
|
* Average trade size: 98.8728 EUR
|
|
198
|
-
* Average trade duration:
|
|
198
|
+
* Average trade duration: 183.5 hours
|
|
199
199
|
╭─────────┬─────────────────────┬─────────────────────┬────────────────────┬──────────────┬──────────────────┬───────────────────────┬────────────────────┬─────────────────────╮
|
|
200
200
|
│ Pair │ Open date │ Close date │ Duration (hours) │ Size (EUR) │ Net gain (EUR) │ Net gain percentage │ Open price (EUR) │ Close price (EUR) │
|
|
201
201
|
├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤
|
|
202
|
-
│ DOT-EUR │ 2023-11-30 20:00:00 │ │
|
|
202
|
+
│ DOT-EUR │ 2023-11-30 20:00:00 │ │ 2976.65 │ 107.104 │ 0 │ 0.0000% │ 5.0215 │ │
|
|
203
203
|
├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤
|
|
204
|
-
│ BTC-EUR │ 2023-11-29 14:00:00 │ │
|
|
204
|
+
│ BTC-EUR │ 2023-11-29 14:00:00 │ │ 3006.65 │ 107.095 │ 0 │ 0.0000% │ 34546.6 │ │
|
|
205
205
|
├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤
|
|
206
|
-
│ BTC-EUR │ 2023-11-08 00:00:00 │ 2023-11-14 16:00:00 │ 160 │ 99.2265 │ 1.3352 │ 1.3456% │ 33075.5 │
|
|
206
|
+
│ BTC-EUR │ 2023-11-08 00:00:00 │ 2023-11-14 16:00:00 │ 160 │ 99.2265 │ 1.3352 │ 1.3456% │ 33075.5 │ 33520.6 │
|
|
207
207
|
├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤
|
|
208
|
-
│ BTC-EUR │ 2023-11-06 16:00:00 │ 2023-11-06 20:00:00 │ 4 │ 97.8607 │ -0.0026 │ -0.0026% │ 32620.2 │
|
|
208
|
+
│ BTC-EUR │ 2023-11-06 16:00:00 │ 2023-11-06 20:00:00 │ 4 │ 97.8607 │ -0.0026 │ -0.0026% │ 32620.2 │ 32619.4 │
|
|
209
209
|
├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤
|
|
210
|
-
│ DOT-EUR │ 2023-10-30 06:00:00 │ 2023-11-
|
|
210
|
+
│ DOT-EUR │ 2023-10-30 06:00:00 │ 2023-11-14 00:00:00 │ 354 │ 100.551 │ 24.8794 │ 24.7430% │ 4.0375 │ 5.0365 │
|
|
211
211
|
├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤
|
|
212
|
-
│ BTC-EUR │ 2023-09-13 16:00:00 │ 2023-09-22 16:00:00 │ 216 │ 97.8529 │ 2.2051 │ 2.2534% │ 24463.2 │
|
|
212
|
+
│ BTC-EUR │ 2023-09-13 16:00:00 │ 2023-09-22 16:00:00 │ 216 │ 97.8529 │ 2.2051 │ 2.2534% │ 24463.2 │ 25014.5 │
|
|
213
213
|
╰─────────┴─────────────────────┴─────────────────────┴────────────────────┴──────────────┴──────────────────┴───────────────────────┴────────────────────┴─────────────────────╯
|
|
214
214
|
==================================================================
|
|
215
215
|
```
|
|
@@ -147,20 +147,20 @@ you will get the following backtesting report:
|
|
|
147
147
|
====================Portfolio overview============================
|
|
148
148
|
* Number of orders: 10
|
|
149
149
|
* Initial balance: 400.0000 EUR
|
|
150
|
-
* Final balance:
|
|
151
|
-
* Total net gain:
|
|
152
|
-
* Total net gain percentage:
|
|
153
|
-
* Growth rate:
|
|
154
|
-
* Growth
|
|
150
|
+
* Final balance: 431.8837 EUR
|
|
151
|
+
* Total net gain: 28.4171 EUR
|
|
152
|
+
* Total net gain percentage: 7.1043%
|
|
153
|
+
* Growth rate: 7.9709%
|
|
154
|
+
* Growth 31.8837 EUR
|
|
155
155
|
====================Positions overview========================
|
|
156
156
|
╭────────────┬──────────┬──────────────────────┬───────────────────────┬──────────────┬───────────────┬───────────────────────────┬────────────────┬───────────────╮
|
|
157
157
|
│ Position │ Amount │ Pending buy amount │ Pending sell amount │ Cost (EUR) │ Value (EUR) │ Percentage of portfolio │ Growth (EUR) │ Growth_rate │
|
|
158
158
|
├────────────┼──────────┼──────────────────────┼───────────────────────┼──────────────┼───────────────┼───────────────────────────┼────────────────┼───────────────┤
|
|
159
|
-
│ EUR │
|
|
159
|
+
│ EUR │ 214.219 │ 0 │ 0 │ 214.219 │ 214.219 │ 49.6010% │ 0 │ 0.0000% │
|
|
160
160
|
├────────────┼──────────┼──────────────────────┼───────────────────────┼──────────────┼───────────────┼───────────────────────────┼────────────────┼───────────────┤
|
|
161
|
-
│ BTC │ 0.
|
|
161
|
+
│ BTC │ 0.0031 │ 0 │ 0 │ 107.095 │ 110.401 │ 25.5627% │ 3.3066 │ 3.0875% │
|
|
162
162
|
├────────────┼──────────┼──────────────────────┼───────────────────────┼──────────────┼───────────────┼───────────────────────────┼────────────────┼───────────────┤
|
|
163
|
-
│ DOT │ 21.
|
|
163
|
+
│ DOT │ 21.3291 │ 0 │ 0 │ 107.104 │ 107.264 │ 24.8363% │ 0.16 │ 0.1494% │
|
|
164
164
|
╰────────────┴──────────┴──────────────────────┴───────────────────────┴──────────────┴───────────────┴───────────────────────────┴────────────────┴───────────────╯
|
|
165
165
|
====================Trades overview===========================
|
|
166
166
|
* Number of trades closed: 4
|
|
@@ -168,21 +168,21 @@ you will get the following backtesting report:
|
|
|
168
168
|
* Percentage of positive trades: 60.0%
|
|
169
169
|
* Percentage of negative trades: 20.0%
|
|
170
170
|
* Average trade size: 98.8728 EUR
|
|
171
|
-
* Average trade duration:
|
|
171
|
+
* Average trade duration: 183.5 hours
|
|
172
172
|
╭─────────┬─────────────────────┬─────────────────────┬────────────────────┬──────────────┬──────────────────┬───────────────────────┬────────────────────┬─────────────────────╮
|
|
173
173
|
│ Pair │ Open date │ Close date │ Duration (hours) │ Size (EUR) │ Net gain (EUR) │ Net gain percentage │ Open price (EUR) │ Close price (EUR) │
|
|
174
174
|
├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤
|
|
175
|
-
│ DOT-EUR │ 2023-11-30 20:00:00 │ │
|
|
175
|
+
│ DOT-EUR │ 2023-11-30 20:00:00 │ │ 2976.65 │ 107.104 │ 0 │ 0.0000% │ 5.0215 │ │
|
|
176
176
|
├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤
|
|
177
|
-
│ BTC-EUR │ 2023-11-29 14:00:00 │ │
|
|
177
|
+
│ BTC-EUR │ 2023-11-29 14:00:00 │ │ 3006.65 │ 107.095 │ 0 │ 0.0000% │ 34546.6 │ │
|
|
178
178
|
├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤
|
|
179
|
-
│ BTC-EUR │ 2023-11-08 00:00:00 │ 2023-11-14 16:00:00 │ 160 │ 99.2265 │ 1.3352 │ 1.3456% │ 33075.5 │
|
|
179
|
+
│ BTC-EUR │ 2023-11-08 00:00:00 │ 2023-11-14 16:00:00 │ 160 │ 99.2265 │ 1.3352 │ 1.3456% │ 33075.5 │ 33520.6 │
|
|
180
180
|
├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤
|
|
181
|
-
│ BTC-EUR │ 2023-11-06 16:00:00 │ 2023-11-06 20:00:00 │ 4 │ 97.8607 │ -0.0026 │ -0.0026% │ 32620.2 │
|
|
181
|
+
│ BTC-EUR │ 2023-11-06 16:00:00 │ 2023-11-06 20:00:00 │ 4 │ 97.8607 │ -0.0026 │ -0.0026% │ 32620.2 │ 32619.4 │
|
|
182
182
|
├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤
|
|
183
|
-
│ DOT-EUR │ 2023-10-30 06:00:00 │ 2023-11-
|
|
183
|
+
│ DOT-EUR │ 2023-10-30 06:00:00 │ 2023-11-14 00:00:00 │ 354 │ 100.551 │ 24.8794 │ 24.7430% │ 4.0375 │ 5.0365 │
|
|
184
184
|
├─────────┼─────────────────────┼─────────────────────┼────────────────────┼──────────────┼──────────────────┼───────────────────────┼────────────────────┼─────────────────────┤
|
|
185
|
-
│ BTC-EUR │ 2023-09-13 16:00:00 │ 2023-09-22 16:00:00 │ 216 │ 97.8529 │ 2.2051 │ 2.2534% │ 24463.2 │
|
|
185
|
+
│ BTC-EUR │ 2023-09-13 16:00:00 │ 2023-09-22 16:00:00 │ 216 │ 97.8529 │ 2.2051 │ 2.2534% │ 24463.2 │ 25014.5 │
|
|
186
186
|
╰─────────┴─────────────────────┴─────────────────────┴────────────────────┴──────────────┴──────────────────┴───────────────────────┴────────────────────┴─────────────────────╯
|
|
187
187
|
==================================================================
|
|
188
188
|
```
|
|
@@ -278,7 +278,13 @@ class App:
|
|
|
278
278
|
backtest_market_data_sources = [
|
|
279
279
|
market_data_source.to_backtest_market_data_source()
|
|
280
280
|
for market_data_source in market_data_sources
|
|
281
|
+
if market_data_source is not None
|
|
281
282
|
]
|
|
283
|
+
|
|
284
|
+
for market_data_source in backtest_market_data_sources:
|
|
285
|
+
if market_data_source is not None:
|
|
286
|
+
market_data_source.config = self.config
|
|
287
|
+
|
|
282
288
|
self.container.market_data_source_service.override(
|
|
283
289
|
BacktestMarketDataSourceService(
|
|
284
290
|
market_data_sources=backtest_market_data_sources,
|
|
@@ -787,6 +793,7 @@ class App:
|
|
|
787
793
|
return reports
|
|
788
794
|
|
|
789
795
|
def add_market_data_source(self, market_data_source):
|
|
796
|
+
market_data_source.config = self.config
|
|
790
797
|
self._market_data_source_service.add(market_data_source)
|
|
791
798
|
|
|
792
799
|
def add_market_credential(self, market_credential: MarketCredential):
|
|
@@ -68,6 +68,7 @@ class DependencyContainer(containers.DeclarativeContainer):
|
|
|
68
68
|
)
|
|
69
69
|
order_service = providers.Factory(
|
|
70
70
|
OrderService,
|
|
71
|
+
configuration_service=configuration_service,
|
|
71
72
|
order_repository=order_repository,
|
|
72
73
|
order_fee_repository=order_fee_repository,
|
|
73
74
|
portfolio_repository=portfolio_repository,
|
|
@@ -125,6 +126,7 @@ class DependencyContainer(containers.DeclarativeContainer):
|
|
|
125
126
|
)
|
|
126
127
|
backtest_service = providers.Factory(
|
|
127
128
|
BacktestService,
|
|
129
|
+
configuration_service=configuration_service,
|
|
128
130
|
order_service=order_service,
|
|
129
131
|
portfolio_repository=portfolio_repository,
|
|
130
132
|
performance_service=performance_service,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
3
|
from dateutil.parser import parse
|
|
4
|
-
from dateutil.tz import gettz
|
|
5
4
|
|
|
6
5
|
from investing_algorithm_framework.domain.exceptions import \
|
|
7
6
|
OperationalException
|
|
@@ -308,10 +307,7 @@ class Order(BaseModel):
|
|
|
308
307
|
remaining=ccxt_order.get("remaining", None),
|
|
309
308
|
cost=ccxt_order.get("cost", None),
|
|
310
309
|
fee=OrderFee.from_ccxt_fee(ccxt_order.get("fee", None)),
|
|
311
|
-
created_at=parse(
|
|
312
|
-
ccxt_order.get("datetime", None),
|
|
313
|
-
tzinfos={"UTC": gettz("UTC")}
|
|
314
|
-
)
|
|
310
|
+
created_at=parse(ccxt_order.get("datetime", None))
|
|
315
311
|
)
|
|
316
312
|
|
|
317
313
|
def __repr__(self):
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
from polars import DataFrame
|
|
3
|
+
import polars as pl
|
|
1
4
|
from datetime import datetime
|
|
2
5
|
from investing_algorithm_framework.domain.models.base_model import BaseModel
|
|
6
|
+
from investing_algorithm_framework.domain.exceptions import \
|
|
7
|
+
OperationalException
|
|
8
|
+
from investing_algorithm_framework.domain.constants import DATETIME_FORMAT
|
|
3
9
|
|
|
4
10
|
|
|
5
11
|
class Trade(BaseModel):
|
|
@@ -164,22 +170,51 @@ class Trade(BaseModel):
|
|
|
164
170
|
return self.absolute_change
|
|
165
171
|
|
|
166
172
|
def is_manual_stop_loss_trigger(
|
|
167
|
-
self,
|
|
173
|
+
self,
|
|
174
|
+
current_price,
|
|
175
|
+
stop_loss_percentage,
|
|
176
|
+
prices: List[float] = None,
|
|
177
|
+
ohlcv_df: DataFrame = None
|
|
168
178
|
):
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
179
|
+
"""
|
|
180
|
+
Function to check if the stop loss is triggered for a given trade.
|
|
181
|
+
|
|
182
|
+
You can use either the prices list or the ohlcv_df DataFrame to
|
|
183
|
+
calculate the stop loss. The dataframe needs to be a Polars
|
|
184
|
+
DataFrame with the following columns: "Datetime" and "Close".
|
|
185
|
+
|
|
186
|
+
You can use the default CCXTOHLCVMarketDataSource to get the ohlcv_df
|
|
187
|
+
DataFrame.
|
|
188
|
+
|
|
189
|
+
Stop loss is triggered when the current price is lower than the
|
|
190
|
+
calculated stop loss price. The stop loss price is calculated by
|
|
191
|
+
taking the highest price of the given range. If the highest price
|
|
192
|
+
is lower than the open price, the stop loss price is calculated by
|
|
193
|
+
taking the open price and subtracting the stop loss percentage.
|
|
194
|
+
If the highest price is higher than the open price, the stop loss
|
|
195
|
+
price is calculated by taking the open price and adding the stop
|
|
196
|
+
loss percentage.
|
|
197
|
+
"""
|
|
198
|
+
|
|
199
|
+
if prices is None and ohlcv_df is None:
|
|
200
|
+
raise OperationalException(
|
|
201
|
+
"Either prices or a polars ohlcv dataframe must be provided"
|
|
202
|
+
)
|
|
177
203
|
|
|
178
204
|
if current_price < self.open_price:
|
|
179
205
|
stop_loss_price = self.open_price * \
|
|
180
206
|
(1 - stop_loss_percentage / 100)
|
|
181
207
|
return current_price <= stop_loss_price
|
|
182
208
|
else:
|
|
209
|
+
# If dataframes are provided, we use the dataframe to calculate
|
|
210
|
+
# the stop loss price
|
|
211
|
+
if ohlcv_df is not None:
|
|
212
|
+
filtered_df = ohlcv_df.filter(
|
|
213
|
+
pl.col('Datetime') >= self.opened_at.strftime(
|
|
214
|
+
DATETIME_FORMAT
|
|
215
|
+
)
|
|
216
|
+
)
|
|
217
|
+
prices = filtered_df['Close'].to_numpy()
|
|
183
218
|
highest_price = max(prices)
|
|
184
219
|
stop_loss_price = highest_price * (1 - stop_loss_percentage / 100)
|
|
185
220
|
return current_price <= stop_loss_price
|
|
@@ -34,6 +34,14 @@ class BacktestMarketDataSource(ABC):
|
|
|
34
34
|
self._backtest_data_start_date = backtest_data_start_date
|
|
35
35
|
self._backtest_data_index_date = backtest_data_index_date
|
|
36
36
|
|
|
37
|
+
@property
|
|
38
|
+
def config(self):
|
|
39
|
+
return self._config
|
|
40
|
+
|
|
41
|
+
@config.setter
|
|
42
|
+
def config(self, value):
|
|
43
|
+
self._config = value
|
|
44
|
+
|
|
37
45
|
def _data_source_exists(self, file_path):
|
|
38
46
|
"""
|
|
39
47
|
Function to check if the data source exists.
|
|
@@ -60,9 +68,7 @@ class BacktestMarketDataSource(ABC):
|
|
|
60
68
|
return False
|
|
61
69
|
|
|
62
70
|
return True
|
|
63
|
-
except Exception
|
|
64
|
-
logger.error(f"Error reading {file_path}")
|
|
65
|
-
logger.error(e)
|
|
71
|
+
except Exception:
|
|
66
72
|
return False
|
|
67
73
|
|
|
68
74
|
def write_data_to_file_path(self, data_file, data):
|
|
@@ -151,10 +157,10 @@ class BacktestMarketDataSource(ABC):
|
|
|
151
157
|
class MarketDataSource(ABC):
|
|
152
158
|
|
|
153
159
|
def __init__(
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
160
|
+
self,
|
|
161
|
+
identifier,
|
|
162
|
+
market,
|
|
163
|
+
symbol,
|
|
158
164
|
):
|
|
159
165
|
self._identifier = identifier
|
|
160
166
|
self._market = market
|
|
@@ -168,6 +174,14 @@ class MarketDataSource(ABC):
|
|
|
168
174
|
def identifier(self):
|
|
169
175
|
return self._identifier
|
|
170
176
|
|
|
177
|
+
@property
|
|
178
|
+
def config(self):
|
|
179
|
+
return self._config
|
|
180
|
+
|
|
181
|
+
@config.setter
|
|
182
|
+
def config(self, value):
|
|
183
|
+
self._config = value
|
|
184
|
+
|
|
171
185
|
def get_identifier(self):
|
|
172
186
|
return self.identifier
|
|
173
187
|
|
|
@@ -3,6 +3,7 @@ import os
|
|
|
3
3
|
from datetime import timedelta
|
|
4
4
|
|
|
5
5
|
import polars
|
|
6
|
+
from dateutil import parser
|
|
6
7
|
|
|
7
8
|
from investing_algorithm_framework.domain import RESOURCE_DIRECTORY, \
|
|
8
9
|
BACKTEST_DATA_DIRECTORY_NAME, DATETIME_FORMAT_BACKTESTING, \
|
|
@@ -59,7 +60,7 @@ class CCXTOHLCVBacktestMarketDataSource(
|
|
|
59
60
|
start_date_func=start_date_func,
|
|
60
61
|
end_date=end_date,
|
|
61
62
|
end_date_func=end_date_func,
|
|
62
|
-
window_size=window_size
|
|
63
|
+
window_size=window_size,
|
|
63
64
|
)
|
|
64
65
|
|
|
65
66
|
def prepare_data(
|
|
@@ -80,7 +81,6 @@ class CCXTOHLCVBacktestMarketDataSource(
|
|
|
80
81
|
When downloading the data it will use the ccxt library.
|
|
81
82
|
"""
|
|
82
83
|
# Calculating the backtest data start date
|
|
83
|
-
|
|
84
84
|
difference = self.end_date - self.start_date
|
|
85
85
|
total_minutes = 0
|
|
86
86
|
|
|
@@ -127,7 +127,10 @@ class CCXTOHLCVBacktestMarketDataSource(
|
|
|
127
127
|
)
|
|
128
128
|
|
|
129
129
|
# Get the OHLCV data from the ccxt market service
|
|
130
|
-
market_service = CCXTMarketService(
|
|
130
|
+
market_service = CCXTMarketService(
|
|
131
|
+
market_credential_service=self.market_credential_service,
|
|
132
|
+
)
|
|
133
|
+
market_service.config = config
|
|
131
134
|
ohlcv = market_service.get_ohlcv(
|
|
132
135
|
symbol=self.symbol,
|
|
133
136
|
time_frame=self.timeframe,
|
|
@@ -171,6 +174,7 @@ class CCXTOHLCVBacktestMarketDataSource(
|
|
|
171
174
|
from_timestamp = backtest_index_date - timedelta(
|
|
172
175
|
minutes=self.total_minutes_timeframe
|
|
173
176
|
)
|
|
177
|
+
datetime_format = self._config["DATETIME_FORMAT"]
|
|
174
178
|
self.backtest_data_index_date = backtest_index_date\
|
|
175
179
|
.replace(microsecond=0)
|
|
176
180
|
from_timestamp = from_timestamp.replace(microsecond=0)
|
|
@@ -193,8 +197,8 @@ class CCXTOHLCVBacktestMarketDataSource(
|
|
|
193
197
|
file_path, columns=self.column_names, separator=","
|
|
194
198
|
)
|
|
195
199
|
df = df.filter(
|
|
196
|
-
(df['Datetime'] >= from_timestamp.strftime(
|
|
197
|
-
& (df['Datetime'] <= to_timestamp.strftime(
|
|
200
|
+
(df['Datetime'] >= from_timestamp.strftime(datetime_format))
|
|
201
|
+
& (df['Datetime'] <= to_timestamp.strftime(datetime_format))
|
|
198
202
|
)
|
|
199
203
|
return df
|
|
200
204
|
|
|
@@ -209,6 +213,9 @@ class CCXTOHLCVBacktestMarketDataSource(
|
|
|
209
213
|
def file_name(self):
|
|
210
214
|
return self._create_file_path().split("/")[-1]
|
|
211
215
|
|
|
216
|
+
def write_data_to_file_path(self, data_file, data: polars.DataFrame):
|
|
217
|
+
data.write_csv(data_file)
|
|
218
|
+
|
|
212
219
|
|
|
213
220
|
class CCXTTickerBacktestMarketDataSource(
|
|
214
221
|
TickerMarketDataSource, BacktestMarketDataSource
|
|
@@ -304,7 +311,10 @@ class CCXTTickerBacktestMarketDataSource(
|
|
|
304
311
|
)
|
|
305
312
|
|
|
306
313
|
# Get the OHLCV data from the ccxt market service
|
|
307
|
-
market_service = CCXTMarketService(
|
|
314
|
+
market_service = CCXTMarketService(
|
|
315
|
+
market_credential_service=self.market_credential_service
|
|
316
|
+
)
|
|
317
|
+
market_service.config = config
|
|
308
318
|
ohlcv = market_service.get_ohlcv(
|
|
309
319
|
symbol=self.symbol,
|
|
310
320
|
time_frame=self.timeframe,
|
|
@@ -363,13 +373,12 @@ class CCXTTickerBacktestMarketDataSource(
|
|
|
363
373
|
# Filter the data based on the backtest index date and the end date
|
|
364
374
|
df = polars.read_csv(file_path)
|
|
365
375
|
df = df.filter(
|
|
366
|
-
(df['Datetime'] >= backtest_index_date
|
|
367
|
-
.strftime(DATETIME_FORMAT))
|
|
376
|
+
(df['Datetime'] >= backtest_index_date.strftime(DATETIME_FORMAT))
|
|
368
377
|
)
|
|
369
|
-
|
|
370
378
|
first_row = df.head(1)[0]
|
|
379
|
+
first_row_datetime = parser.parse(first_row["Datetime"][0])
|
|
371
380
|
|
|
372
|
-
if
|
|
381
|
+
if first_row_datetime > end_date:
|
|
373
382
|
logger.warning(
|
|
374
383
|
f"No ticker data available for the given backtest "
|
|
375
384
|
f"index date {backtest_index_date} and symbol {self.symbol} "
|
|
@@ -386,12 +395,17 @@ class CCXTTickerBacktestMarketDataSource(
|
|
|
386
395
|
"datetime": first_row["Datetime"][0],
|
|
387
396
|
}
|
|
388
397
|
|
|
398
|
+
def write_data_to_file_path(self, data_file, data: polars.DataFrame):
|
|
399
|
+
data.write_csv(data_file)
|
|
400
|
+
|
|
389
401
|
|
|
390
402
|
class CCXTOHLCVMarketDataSource(OHLCVMarketDataSource):
|
|
391
403
|
|
|
392
404
|
def get_data(self, **kwargs):
|
|
393
|
-
market_service = CCXTMarketService(
|
|
394
|
-
|
|
405
|
+
market_service = CCXTMarketService(
|
|
406
|
+
market_credential_service=self.market_credential_service,
|
|
407
|
+
)
|
|
408
|
+
market_service.config = self.config
|
|
395
409
|
if self.start_date is None:
|
|
396
410
|
raise OperationalException(
|
|
397
411
|
"Either start_date or start_date_func should be set "
|
|
@@ -422,7 +436,10 @@ class CCXTOHLCVMarketDataSource(OHLCVMarketDataSource):
|
|
|
422
436
|
class CCXTOrderBookMarketDataSource(OrderBookMarketDataSource):
|
|
423
437
|
|
|
424
438
|
def get_data(self, **kwargs):
|
|
425
|
-
market_service = CCXTMarketService(
|
|
439
|
+
market_service = CCXTMarketService(
|
|
440
|
+
market_credential_service=self.market_credential_service
|
|
441
|
+
)
|
|
442
|
+
market_service.config = self.config
|
|
426
443
|
return market_service.get_order_book(
|
|
427
444
|
symbol=self.symbol, market=self.market
|
|
428
445
|
)
|
|
@@ -438,7 +455,8 @@ class CCXTTickerMarketDataSource(TickerMarketDataSource):
|
|
|
438
455
|
identifier,
|
|
439
456
|
market,
|
|
440
457
|
symbol=None,
|
|
441
|
-
backtest_timeframe=None
|
|
458
|
+
backtest_timeframe=None,
|
|
459
|
+
|
|
442
460
|
):
|
|
443
461
|
super().__init__(
|
|
444
462
|
identifier=identifier,
|
|
@@ -448,7 +466,10 @@ class CCXTTickerMarketDataSource(TickerMarketDataSource):
|
|
|
448
466
|
self._backtest_timeframe = backtest_timeframe
|
|
449
467
|
|
|
450
468
|
def get_data(self, **kwargs):
|
|
451
|
-
market_service = CCXTMarketService(
|
|
469
|
+
market_service = CCXTMarketService(
|
|
470
|
+
market_credential_service=self.market_credential_service
|
|
471
|
+
)
|
|
472
|
+
market_service.config = self.config
|
|
452
473
|
|
|
453
474
|
if self.market is None:
|
|
454
475
|
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
+
import polars
|
|
3
|
+
import logging
|
|
2
4
|
|
|
3
|
-
import pandas as pd
|
|
4
5
|
from dateutil.parser import parse
|
|
5
6
|
|
|
6
7
|
from investing_algorithm_framework.domain import OHLCVMarketDataSource, \
|
|
7
|
-
BacktestMarketDataSource, OperationalException, TickerMarketDataSource
|
|
8
|
+
BacktestMarketDataSource, OperationalException, TickerMarketDataSource, \
|
|
9
|
+
DATETIME_FORMAT
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
8
12
|
|
|
9
13
|
|
|
10
14
|
class CSVOHLCVMarketDataSource(OHLCVMarketDataSource):
|
|
@@ -44,8 +48,9 @@ class CSVOHLCVMarketDataSource(OHLCVMarketDataSource):
|
|
|
44
48
|
self._columns = [
|
|
45
49
|
"Datetime", "Open", "High", "Low", "Close", "Volume"
|
|
46
50
|
]
|
|
47
|
-
df =
|
|
51
|
+
df = polars.read_csv(csv_file_path)
|
|
48
52
|
|
|
53
|
+
# Check if all column names are in the csv file
|
|
49
54
|
if not all(column in df.columns for column in self._columns):
|
|
50
55
|
# Identify missing columns
|
|
51
56
|
missing_columns = [column for column in self._columns if
|
|
@@ -56,10 +61,10 @@ class CSVOHLCVMarketDataSource(OHLCVMarketDataSource):
|
|
|
56
61
|
f"Missing columns: {missing_columns}"
|
|
57
62
|
)
|
|
58
63
|
|
|
59
|
-
first_row = df.
|
|
60
|
-
last_row = df.
|
|
61
|
-
self._start_date = parse(first_row[0])
|
|
62
|
-
self._end_date = parse(last_row[0])
|
|
64
|
+
first_row = df.head(1)
|
|
65
|
+
last_row = df.tail(1)
|
|
66
|
+
self._start_date = parse(first_row["Datetime"][0])
|
|
67
|
+
self._end_date = parse(last_row["Datetime"][0])
|
|
63
68
|
|
|
64
69
|
@property
|
|
65
70
|
def csv_file_path(self):
|
|
@@ -67,40 +72,25 @@ class CSVOHLCVMarketDataSource(OHLCVMarketDataSource):
|
|
|
67
72
|
|
|
68
73
|
def get_data(
|
|
69
74
|
self,
|
|
70
|
-
|
|
71
|
-
|
|
75
|
+
from_timestamp=None,
|
|
76
|
+
to_timestamp=None,
|
|
72
77
|
**kwargs
|
|
73
78
|
):
|
|
74
79
|
|
|
75
|
-
if
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if to_time_stamp is None:
|
|
79
|
-
to_time_stamp = self.end_date
|
|
80
|
-
|
|
81
|
-
df = pd.read_csv(self._csv_file_path)
|
|
82
|
-
|
|
83
|
-
# Convert the 'Datetime' column to datetime type if
|
|
84
|
-
# it's not already
|
|
85
|
-
if 'Datetime' in df.columns and pd.api.types.is_string_dtype(
|
|
86
|
-
df['Datetime']):
|
|
87
|
-
df['Datetime'] = pd.to_datetime(df['Datetime'], utc=True)
|
|
88
|
-
|
|
89
|
-
# Filter rows based on the start and end dates
|
|
90
|
-
filtered_df = df[
|
|
91
|
-
(df['Datetime'] >= from_time_stamp)
|
|
92
|
-
& (df['Datetime'] <= to_time_stamp)
|
|
93
|
-
]
|
|
94
|
-
|
|
95
|
-
# Specify the columns you want in the inner lists
|
|
96
|
-
selected_columns = ["Datetime", "Open", "High", "Low", "Close",
|
|
97
|
-
"Volume"]
|
|
80
|
+
if from_timestamp is None:
|
|
81
|
+
from_timestamp = self.start_date
|
|
98
82
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
self.dataframe_to_list_of_lists(filtered_df, selected_columns)
|
|
83
|
+
if to_timestamp is None:
|
|
84
|
+
to_timestamp = self.end_date
|
|
102
85
|
|
|
103
|
-
|
|
86
|
+
df = polars.read_csv(
|
|
87
|
+
self.csv_file_path, columns=self._columns, separator=","
|
|
88
|
+
)
|
|
89
|
+
df = df.filter(
|
|
90
|
+
(df['Datetime'] >= from_timestamp.strftime(DATETIME_FORMAT))
|
|
91
|
+
& (df['Datetime'] <= to_timestamp.strftime(DATETIME_FORMAT))
|
|
92
|
+
)
|
|
93
|
+
return df
|
|
104
94
|
|
|
105
95
|
def dataframe_to_list_of_lists(self, dataframe, columns):
|
|
106
96
|
# Extract selected columns from DataFrame and convert
|
|
@@ -130,7 +120,7 @@ class CSVTickerMarketDataSource(TickerMarketDataSource):
|
|
|
130
120
|
self._columns = [
|
|
131
121
|
"Datetime", "Open", "High", "Low", "Close", "Volume"
|
|
132
122
|
]
|
|
133
|
-
df =
|
|
123
|
+
df = polars.read_csv(self._csv_file_path)
|
|
134
124
|
|
|
135
125
|
if not all(column in df.columns for column in self._columns):
|
|
136
126
|
# Identify missing columns
|
|
@@ -151,27 +141,30 @@ class CSVTickerMarketDataSource(TickerMarketDataSource):
|
|
|
151
141
|
if index_datetime is None:
|
|
152
142
|
index_datetime = datetime.utcnow()
|
|
153
143
|
|
|
154
|
-
|
|
155
|
-
df =
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
df['Datetime']):
|
|
161
|
-
df['Datetime'] = pd.to_datetime(df['Datetime'], utc=True)
|
|
144
|
+
# Filter the data based on the backtest index date and the end date
|
|
145
|
+
df = polars.read_csv(self._csv_file_path)
|
|
146
|
+
df = df.filter(
|
|
147
|
+
(df['Datetime'] >= index_datetime
|
|
148
|
+
.strftime(DATETIME_FORMAT))
|
|
149
|
+
)
|
|
162
150
|
|
|
163
|
-
#
|
|
164
|
-
|
|
151
|
+
# Check if the dataframe is empty
|
|
152
|
+
if df.shape[0] == 0:
|
|
153
|
+
raise OperationalException(
|
|
154
|
+
f"No ticker data found for {self.symbol} "
|
|
155
|
+
f"at {index_datetime}"
|
|
156
|
+
)
|
|
165
157
|
|
|
166
|
-
|
|
167
|
-
return None
|
|
158
|
+
first_row = df.head(1)[0]
|
|
168
159
|
|
|
169
|
-
|
|
160
|
+
# Calculate the bid and ask price based on the high and low price
|
|
170
161
|
return {
|
|
171
162
|
"symbol": self.symbol,
|
|
172
|
-
"bid":
|
|
173
|
-
|
|
174
|
-
"
|
|
163
|
+
"bid": float((first_row["Low"][0])
|
|
164
|
+
+ float(first_row["High"][0])) / 2,
|
|
165
|
+
"ask": float((first_row["Low"][0])
|
|
166
|
+
+ float(first_row["High"][0])) / 2,
|
|
167
|
+
"datetime": first_row["Datetime"][0],
|
|
175
168
|
}
|
|
176
169
|
|
|
177
170
|
def dataframe_to_list_of_lists(self, dataframe, columns):
|