investing-algorithm-framework 1.5__py3-none-any.whl → 7.25.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- investing_algorithm_framework/__init__.py +192 -16
- investing_algorithm_framework/analysis/__init__.py +16 -0
- investing_algorithm_framework/analysis/backtest_data_ranges.py +202 -0
- investing_algorithm_framework/analysis/data.py +170 -0
- investing_algorithm_framework/analysis/markdown.py +91 -0
- investing_algorithm_framework/analysis/ranking.py +298 -0
- investing_algorithm_framework/app/__init__.py +29 -4
- investing_algorithm_framework/app/algorithm/__init__.py +7 -0
- investing_algorithm_framework/app/algorithm/algorithm.py +193 -0
- investing_algorithm_framework/app/algorithm/algorithm_factory.py +118 -0
- investing_algorithm_framework/app/app.py +2220 -379
- investing_algorithm_framework/app/app_hook.py +28 -0
- investing_algorithm_framework/app/context.py +1724 -0
- investing_algorithm_framework/app/eventloop.py +620 -0
- investing_algorithm_framework/app/reporting/__init__.py +27 -0
- investing_algorithm_framework/app/reporting/ascii.py +921 -0
- investing_algorithm_framework/app/reporting/backtest_report.py +349 -0
- investing_algorithm_framework/app/reporting/charts/__init__.py +19 -0
- investing_algorithm_framework/app/reporting/charts/entry_exist_signals.py +66 -0
- investing_algorithm_framework/app/reporting/charts/equity_curve.py +37 -0
- investing_algorithm_framework/app/reporting/charts/equity_curve_drawdown.py +74 -0
- investing_algorithm_framework/app/reporting/charts/line_chart.py +11 -0
- investing_algorithm_framework/app/reporting/charts/monthly_returns_heatmap.py +70 -0
- investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +51 -0
- investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +79 -0
- investing_algorithm_framework/app/reporting/charts/yearly_returns_barchart.py +55 -0
- investing_algorithm_framework/app/reporting/generate.py +185 -0
- investing_algorithm_framework/app/reporting/tables/__init__.py +11 -0
- investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +217 -0
- investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +80 -0
- investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +147 -0
- investing_algorithm_framework/app/reporting/tables/trades_table.py +75 -0
- investing_algorithm_framework/app/reporting/tables/utils.py +29 -0
- investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +154 -0
- investing_algorithm_framework/app/stateless/action_handlers/__init__.py +6 -3
- investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +1 -1
- investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +2 -1
- investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +14 -7
- investing_algorithm_framework/app/strategy.py +867 -60
- investing_algorithm_framework/app/task.py +5 -3
- investing_algorithm_framework/app/web/__init__.py +2 -1
- investing_algorithm_framework/app/web/controllers/__init__.py +2 -2
- investing_algorithm_framework/app/web/controllers/orders.py +3 -2
- investing_algorithm_framework/app/web/controllers/positions.py +2 -2
- investing_algorithm_framework/app/web/create_app.py +4 -2
- investing_algorithm_framework/app/web/schemas/position.py +1 -0
- investing_algorithm_framework/cli/__init__.py +0 -0
- investing_algorithm_framework/cli/cli.py +231 -0
- investing_algorithm_framework/cli/deploy_to_aws_lambda.py +501 -0
- investing_algorithm_framework/cli/deploy_to_azure_function.py +718 -0
- investing_algorithm_framework/cli/initialize_app.py +603 -0
- investing_algorithm_framework/cli/templates/.gitignore.template +178 -0
- investing_algorithm_framework/cli/templates/app.py.template +18 -0
- investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +48 -0
- investing_algorithm_framework/cli/templates/app_azure_function.py.template +14 -0
- investing_algorithm_framework/cli/templates/app_web.py.template +18 -0
- investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +22 -0
- investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +92 -0
- investing_algorithm_framework/cli/templates/aws_lambda_readme.md.template +110 -0
- investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +2 -0
- investing_algorithm_framework/cli/templates/azure_function_function_app.py.template +65 -0
- investing_algorithm_framework/cli/templates/azure_function_host.json.template +15 -0
- investing_algorithm_framework/cli/templates/azure_function_local.settings.json.template +8 -0
- investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +3 -0
- investing_algorithm_framework/cli/templates/data_providers.py.template +17 -0
- investing_algorithm_framework/cli/templates/env.example.template +2 -0
- investing_algorithm_framework/cli/templates/env_azure_function.example.template +4 -0
- investing_algorithm_framework/cli/templates/market_data_providers.py.template +9 -0
- investing_algorithm_framework/cli/templates/readme.md.template +135 -0
- investing_algorithm_framework/cli/templates/requirements.txt.template +2 -0
- investing_algorithm_framework/cli/templates/run_backtest.py.template +20 -0
- investing_algorithm_framework/cli/templates/strategy.py.template +124 -0
- investing_algorithm_framework/cli/validate_backtest_checkpoints.py +197 -0
- investing_algorithm_framework/create_app.py +40 -7
- investing_algorithm_framework/dependency_container.py +100 -47
- investing_algorithm_framework/domain/__init__.py +97 -30
- investing_algorithm_framework/domain/algorithm_id.py +69 -0
- investing_algorithm_framework/domain/backtesting/__init__.py +25 -0
- investing_algorithm_framework/domain/backtesting/backtest.py +548 -0
- investing_algorithm_framework/domain/backtesting/backtest_date_range.py +113 -0
- investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +241 -0
- investing_algorithm_framework/domain/backtesting/backtest_metrics.py +470 -0
- investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +275 -0
- investing_algorithm_framework/domain/backtesting/backtest_run.py +663 -0
- investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +162 -0
- investing_algorithm_framework/domain/backtesting/backtest_utils.py +198 -0
- investing_algorithm_framework/domain/backtesting/combine_backtests.py +392 -0
- investing_algorithm_framework/domain/config.py +59 -136
- investing_algorithm_framework/domain/constants.py +18 -37
- investing_algorithm_framework/domain/data_provider.py +334 -0
- investing_algorithm_framework/domain/data_structures.py +42 -0
- investing_algorithm_framework/domain/exceptions.py +51 -1
- investing_algorithm_framework/domain/models/__init__.py +26 -19
- investing_algorithm_framework/domain/models/app_mode.py +34 -0
- investing_algorithm_framework/domain/models/data/__init__.py +7 -0
- investing_algorithm_framework/domain/models/data/data_source.py +222 -0
- investing_algorithm_framework/domain/models/data/data_type.py +46 -0
- investing_algorithm_framework/domain/models/event.py +35 -0
- investing_algorithm_framework/domain/models/market/__init__.py +5 -0
- investing_algorithm_framework/domain/models/market/market_credential.py +88 -0
- investing_algorithm_framework/domain/models/order/__init__.py +3 -4
- investing_algorithm_framework/domain/models/order/order.py +198 -65
- investing_algorithm_framework/domain/models/order/order_status.py +2 -2
- investing_algorithm_framework/domain/models/order/order_type.py +1 -3
- investing_algorithm_framework/domain/models/portfolio/__init__.py +6 -2
- investing_algorithm_framework/domain/models/portfolio/portfolio.py +98 -3
- investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +37 -43
- investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +108 -11
- investing_algorithm_framework/domain/models/position/__init__.py +2 -1
- investing_algorithm_framework/domain/models/position/position.py +20 -0
- investing_algorithm_framework/domain/models/position/position_size.py +41 -0
- investing_algorithm_framework/domain/models/position/position_snapshot.py +0 -2
- investing_algorithm_framework/domain/models/risk_rules/__init__.py +7 -0
- investing_algorithm_framework/domain/models/risk_rules/stop_loss_rule.py +51 -0
- investing_algorithm_framework/domain/models/risk_rules/take_profit_rule.py +55 -0
- investing_algorithm_framework/domain/models/snapshot_interval.py +45 -0
- investing_algorithm_framework/domain/models/strategy_profile.py +19 -141
- investing_algorithm_framework/domain/models/time_frame.py +94 -98
- investing_algorithm_framework/domain/models/time_interval.py +33 -0
- investing_algorithm_framework/domain/models/time_unit.py +66 -2
- investing_algorithm_framework/domain/models/tracing/__init__.py +0 -0
- investing_algorithm_framework/domain/models/tracing/trace.py +23 -0
- investing_algorithm_framework/domain/models/trade/__init__.py +11 -0
- investing_algorithm_framework/domain/models/trade/trade.py +389 -0
- investing_algorithm_framework/domain/models/trade/trade_status.py +40 -0
- investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +332 -0
- investing_algorithm_framework/domain/models/trade/trade_take_profit.py +365 -0
- investing_algorithm_framework/domain/order_executor.py +112 -0
- investing_algorithm_framework/domain/portfolio_provider.py +118 -0
- investing_algorithm_framework/domain/services/__init__.py +11 -0
- investing_algorithm_framework/domain/services/market_credential_service.py +37 -0
- investing_algorithm_framework/domain/services/portfolios/__init__.py +5 -0
- investing_algorithm_framework/domain/services/portfolios/portfolio_sync_service.py +9 -0
- investing_algorithm_framework/domain/services/rounding_service.py +27 -0
- investing_algorithm_framework/domain/services/state_handler.py +38 -0
- investing_algorithm_framework/domain/strategy.py +1 -29
- investing_algorithm_framework/domain/utils/__init__.py +15 -5
- investing_algorithm_framework/domain/utils/csv.py +22 -0
- investing_algorithm_framework/domain/utils/custom_tqdm.py +22 -0
- investing_algorithm_framework/domain/utils/dates.py +57 -0
- investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +19 -0
- investing_algorithm_framework/domain/utils/polars.py +53 -0
- investing_algorithm_framework/domain/utils/random.py +29 -0
- investing_algorithm_framework/download_data.py +244 -0
- investing_algorithm_framework/infrastructure/__init__.py +37 -11
- investing_algorithm_framework/infrastructure/data_providers/__init__.py +36 -0
- investing_algorithm_framework/infrastructure/data_providers/ccxt.py +1152 -0
- investing_algorithm_framework/infrastructure/data_providers/csv.py +568 -0
- investing_algorithm_framework/infrastructure/data_providers/pandas.py +599 -0
- investing_algorithm_framework/infrastructure/database/__init__.py +6 -2
- investing_algorithm_framework/infrastructure/database/sql_alchemy.py +86 -12
- investing_algorithm_framework/infrastructure/models/__init__.py +7 -3
- investing_algorithm_framework/infrastructure/models/order/__init__.py +2 -2
- investing_algorithm_framework/infrastructure/models/order/order.py +53 -53
- investing_algorithm_framework/infrastructure/models/order/order_metadata.py +44 -0
- investing_algorithm_framework/infrastructure/models/order_trade_association.py +10 -0
- investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +1 -1
- investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +8 -2
- investing_algorithm_framework/infrastructure/models/portfolio/{portfolio.py → sql_portfolio.py} +17 -6
- investing_algorithm_framework/infrastructure/models/position/position_snapshot.py +3 -1
- investing_algorithm_framework/infrastructure/models/trades/__init__.py +9 -0
- investing_algorithm_framework/infrastructure/models/trades/trade.py +130 -0
- investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +59 -0
- investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +55 -0
- investing_algorithm_framework/infrastructure/order_executors/__init__.py +21 -0
- investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +28 -0
- investing_algorithm_framework/infrastructure/order_executors/ccxt_order_executor.py +200 -0
- investing_algorithm_framework/infrastructure/portfolio_providers/__init__.py +19 -0
- investing_algorithm_framework/infrastructure/portfolio_providers/ccxt_portfolio_provider.py +199 -0
- investing_algorithm_framework/infrastructure/repositories/__init__.py +10 -4
- investing_algorithm_framework/infrastructure/repositories/order_metadata_repository.py +17 -0
- investing_algorithm_framework/infrastructure/repositories/order_repository.py +16 -5
- investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +2 -2
- investing_algorithm_framework/infrastructure/repositories/position_repository.py +11 -0
- investing_algorithm_framework/infrastructure/repositories/repository.py +84 -30
- investing_algorithm_framework/infrastructure/repositories/trade_repository.py +71 -0
- investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +29 -0
- investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +29 -0
- investing_algorithm_framework/infrastructure/services/__init__.py +9 -4
- investing_algorithm_framework/infrastructure/services/aws/__init__.py +6 -0
- investing_algorithm_framework/infrastructure/services/aws/state_handler.py +193 -0
- investing_algorithm_framework/infrastructure/services/azure/__init__.py +5 -0
- investing_algorithm_framework/infrastructure/services/azure/state_handler.py +158 -0
- investing_algorithm_framework/infrastructure/services/backtesting/__init__.py +9 -0
- investing_algorithm_framework/infrastructure/services/backtesting/backtest_service.py +2596 -0
- investing_algorithm_framework/infrastructure/services/backtesting/event_backtest_service.py +285 -0
- investing_algorithm_framework/infrastructure/services/backtesting/vector_backtest_service.py +468 -0
- investing_algorithm_framework/services/__init__.py +123 -15
- investing_algorithm_framework/services/configuration_service.py +77 -11
- investing_algorithm_framework/services/data_providers/__init__.py +5 -0
- investing_algorithm_framework/services/data_providers/data_provider_service.py +1058 -0
- investing_algorithm_framework/services/market_credential_service.py +40 -0
- investing_algorithm_framework/services/metrics/__init__.py +119 -0
- investing_algorithm_framework/services/metrics/alpha.py +0 -0
- investing_algorithm_framework/services/metrics/beta.py +0 -0
- investing_algorithm_framework/services/metrics/cagr.py +60 -0
- investing_algorithm_framework/services/metrics/calmar_ratio.py +40 -0
- investing_algorithm_framework/services/metrics/drawdown.py +218 -0
- investing_algorithm_framework/services/metrics/equity_curve.py +24 -0
- investing_algorithm_framework/services/metrics/exposure.py +210 -0
- investing_algorithm_framework/services/metrics/generate.py +358 -0
- investing_algorithm_framework/services/metrics/mean_daily_return.py +84 -0
- investing_algorithm_framework/services/metrics/price_efficiency.py +57 -0
- investing_algorithm_framework/services/metrics/profit_factor.py +165 -0
- investing_algorithm_framework/services/metrics/recovery.py +113 -0
- investing_algorithm_framework/services/metrics/returns.py +452 -0
- investing_algorithm_framework/services/metrics/risk_free_rate.py +28 -0
- investing_algorithm_framework/services/metrics/sharpe_ratio.py +137 -0
- investing_algorithm_framework/services/metrics/sortino_ratio.py +74 -0
- investing_algorithm_framework/services/metrics/standard_deviation.py +156 -0
- investing_algorithm_framework/services/metrics/trades.py +473 -0
- investing_algorithm_framework/services/metrics/treynor_ratio.py +0 -0
- investing_algorithm_framework/services/metrics/ulcer.py +0 -0
- investing_algorithm_framework/services/metrics/value_at_risk.py +0 -0
- investing_algorithm_framework/services/metrics/volatility.py +118 -0
- investing_algorithm_framework/services/metrics/win_rate.py +177 -0
- investing_algorithm_framework/services/order_service/__init__.py +9 -0
- investing_algorithm_framework/services/order_service/order_backtest_service.py +178 -0
- investing_algorithm_framework/services/order_service/order_executor_lookup.py +110 -0
- investing_algorithm_framework/services/order_service/order_service.py +826 -0
- investing_algorithm_framework/services/portfolios/__init__.py +16 -0
- investing_algorithm_framework/services/portfolios/backtest_portfolio_service.py +54 -0
- investing_algorithm_framework/services/{portfolio_configuration_service.py → portfolios/portfolio_configuration_service.py} +27 -12
- investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +106 -0
- investing_algorithm_framework/services/portfolios/portfolio_service.py +188 -0
- investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +136 -0
- investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +182 -0
- investing_algorithm_framework/services/positions/__init__.py +7 -0
- investing_algorithm_framework/services/positions/position_service.py +210 -0
- investing_algorithm_framework/services/repository_service.py +8 -2
- investing_algorithm_framework/services/trade_order_evaluator/__init__.py +9 -0
- investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +117 -0
- investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +51 -0
- investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +80 -0
- investing_algorithm_framework/services/trade_service/__init__.py +9 -0
- investing_algorithm_framework/services/trade_service/trade_service.py +1099 -0
- investing_algorithm_framework/services/trade_service/trade_stop_loss_service.py +39 -0
- investing_algorithm_framework/services/trade_service/trade_take_profit_service.py +41 -0
- investing_algorithm_framework-7.25.6.dist-info/METADATA +535 -0
- investing_algorithm_framework-7.25.6.dist-info/RECORD +268 -0
- {investing_algorithm_framework-1.5.dist-info → investing_algorithm_framework-7.25.6.dist-info}/WHEEL +1 -2
- investing_algorithm_framework-7.25.6.dist-info/entry_points.txt +3 -0
- investing_algorithm_framework/app/algorithm.py +0 -630
- investing_algorithm_framework/domain/models/backtest_profile.py +0 -414
- investing_algorithm_framework/domain/models/market_data/__init__.py +0 -11
- investing_algorithm_framework/domain/models/market_data/asset_price.py +0 -50
- investing_algorithm_framework/domain/models/market_data/ohlcv.py +0 -105
- investing_algorithm_framework/domain/models/market_data/order_book.py +0 -63
- investing_algorithm_framework/domain/models/market_data/ticker.py +0 -92
- investing_algorithm_framework/domain/models/order/order_fee.py +0 -45
- investing_algorithm_framework/domain/models/trade.py +0 -78
- investing_algorithm_framework/domain/models/trading_data_types.py +0 -47
- investing_algorithm_framework/domain/models/trading_time_frame.py +0 -223
- investing_algorithm_framework/domain/singleton.py +0 -9
- investing_algorithm_framework/domain/utils/backtesting.py +0 -82
- investing_algorithm_framework/infrastructure/models/order/order_fee.py +0 -21
- investing_algorithm_framework/infrastructure/repositories/order_fee_repository.py +0 -15
- investing_algorithm_framework/infrastructure/services/market_backtest_service.py +0 -360
- investing_algorithm_framework/infrastructure/services/market_service.py +0 -410
- investing_algorithm_framework/infrastructure/services/performance_service.py +0 -192
- investing_algorithm_framework/services/backtest_service.py +0 -268
- investing_algorithm_framework/services/market_data_service.py +0 -77
- investing_algorithm_framework/services/order_backtest_service.py +0 -122
- investing_algorithm_framework/services/order_service.py +0 -752
- investing_algorithm_framework/services/portfolio_service.py +0 -164
- investing_algorithm_framework/services/portfolio_snapshot_service.py +0 -68
- investing_algorithm_framework/services/position_cost_service.py +0 -5
- investing_algorithm_framework/services/position_service.py +0 -63
- investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -225
- investing_algorithm_framework-1.5.dist-info/AUTHORS.md +0 -8
- investing_algorithm_framework-1.5.dist-info/METADATA +0 -230
- investing_algorithm_framework-1.5.dist-info/RECORD +0 -119
- investing_algorithm_framework-1.5.dist-info/top_level.txt +0 -1
- /investing_algorithm_framework/{infrastructure/services/performance_backtest_service.py → app/reporting/tables/stop_loss_table.py} +0 -0
- /investing_algorithm_framework/services/{position_snapshot_service.py → positions/position_snapshot_service.py} +0 -0
- {investing_algorithm_framework-1.5.dist-info → investing_algorithm_framework-7.25.6.dist-info}/LICENSE +0 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from datetime import datetime, timezone, timedelta
|
|
3
|
+
from typing import Union
|
|
4
|
+
|
|
5
|
+
from dateutil import parser
|
|
6
|
+
|
|
7
|
+
from investing_algorithm_framework.domain.models.time_frame import TimeFrame
|
|
8
|
+
from .data_type import DataType
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(frozen=True)
|
|
12
|
+
class DataSource:
|
|
13
|
+
"""
|
|
14
|
+
Data registration model. Defines the data source for a strategy. A simple
|
|
15
|
+
data source can be defined as:
|
|
16
|
+
DataSource(
|
|
17
|
+
symbol="BTC/EUR",
|
|
18
|
+
data_type="ohlcv",
|
|
19
|
+
window_size=200,
|
|
20
|
+
market="BITVAVO",
|
|
21
|
+
identifier="BTC/EUR_ohlcv"
|
|
22
|
+
)
|
|
23
|
+
"""
|
|
24
|
+
identifier: str = None
|
|
25
|
+
data_provider_identifier: str = None
|
|
26
|
+
data_type: Union[DataType, str] = None
|
|
27
|
+
symbol: str = None
|
|
28
|
+
window_size: int = None
|
|
29
|
+
time_frame: Union[TimeFrame, str] = None
|
|
30
|
+
market: str = None
|
|
31
|
+
storage_path: str = None
|
|
32
|
+
pandas: bool = False
|
|
33
|
+
date: Union[datetime, None] = None
|
|
34
|
+
start_date: Union[datetime, None] = None
|
|
35
|
+
end_date: Union[datetime, None] = None
|
|
36
|
+
save: bool = False
|
|
37
|
+
|
|
38
|
+
def __post_init__(self):
|
|
39
|
+
# Convert data_type and time_frame to their respective enums if needed
|
|
40
|
+
if isinstance(self.data_type, str):
|
|
41
|
+
object.__setattr__(self, 'data_type',
|
|
42
|
+
DataType.from_string(self.data_type))
|
|
43
|
+
|
|
44
|
+
if isinstance(self.time_frame, str):
|
|
45
|
+
object.__setattr__(self, 'time_frame',
|
|
46
|
+
TimeFrame.from_string(self.time_frame))
|
|
47
|
+
|
|
48
|
+
start_date = self.start_date
|
|
49
|
+
end_date = self.end_date
|
|
50
|
+
|
|
51
|
+
# Parse the start_date if it is a string and
|
|
52
|
+
# make sure its set to timezone utc
|
|
53
|
+
if start_date is None:
|
|
54
|
+
|
|
55
|
+
if isinstance(self.start_date, str):
|
|
56
|
+
start_date = parser.parse(start_date)
|
|
57
|
+
|
|
58
|
+
if start_date is not None:
|
|
59
|
+
object.__setattr__(
|
|
60
|
+
self,
|
|
61
|
+
'start_date',
|
|
62
|
+
start_date.replace(tzinfo=timezone.utc)
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
# Parse the end_date if it is a string and
|
|
66
|
+
# make sure its set to timezone utc
|
|
67
|
+
if end_date is None:
|
|
68
|
+
|
|
69
|
+
if isinstance(self.end_date, str):
|
|
70
|
+
end_date = parser.parse(end_date)
|
|
71
|
+
|
|
72
|
+
if end_date is not None:
|
|
73
|
+
object.__setattr__(
|
|
74
|
+
self,
|
|
75
|
+
'end_date',
|
|
76
|
+
end_date.replace(tzinfo=timezone.utc)
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
if self.market is not None:
|
|
80
|
+
object.__setattr__(self, 'market', self.market.upper())
|
|
81
|
+
|
|
82
|
+
if self.symbol is not None:
|
|
83
|
+
object.__setattr__(self, 'symbol', self.symbol.upper())
|
|
84
|
+
|
|
85
|
+
def get_identifier(self):
|
|
86
|
+
"""
|
|
87
|
+
Returns the identifier or creates a unique identifier for the
|
|
88
|
+
data source based on its attributes.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
if self.identifier is not None:
|
|
92
|
+
return self.identifier
|
|
93
|
+
|
|
94
|
+
if DataType.OHLCV.equals(self.data_type):
|
|
95
|
+
return (f"{self.data_type.value}_{self.market}_"
|
|
96
|
+
f"{self.symbol}_{self.time_frame.value}")
|
|
97
|
+
|
|
98
|
+
elif DataType.CUSTOM.equals(self.data_type):
|
|
99
|
+
identifier = "CUSTOM"
|
|
100
|
+
|
|
101
|
+
if self.symbol is not None:
|
|
102
|
+
identifier += f"_{self.symbol}"
|
|
103
|
+
|
|
104
|
+
if self.time_frame is not None:
|
|
105
|
+
identifier += f"_{self.time_frame.value}"
|
|
106
|
+
|
|
107
|
+
if self.market is not None:
|
|
108
|
+
identifier += f"_{self.market}"
|
|
109
|
+
|
|
110
|
+
if self.window_size is not None:
|
|
111
|
+
identifier += f"_{self.window_size}"
|
|
112
|
+
|
|
113
|
+
return identifier
|
|
114
|
+
|
|
115
|
+
def to_dict(self):
|
|
116
|
+
"""
|
|
117
|
+
Converts the DataSource instance to a dictionary.
|
|
118
|
+
"""
|
|
119
|
+
non_null_attributes = {
|
|
120
|
+
key: value for key, value in self.__dict__.items()
|
|
121
|
+
if value is not None
|
|
122
|
+
}
|
|
123
|
+
# Convert DataType and TimeFrame to their string representations
|
|
124
|
+
if self.data_type is not None:
|
|
125
|
+
non_null_attributes['data_type'] = self.data_type.value
|
|
126
|
+
if self.time_frame is not None:
|
|
127
|
+
non_null_attributes['time_frame'] = self.time_frame.value
|
|
128
|
+
|
|
129
|
+
return non_null_attributes
|
|
130
|
+
|
|
131
|
+
def __repr__(self):
|
|
132
|
+
return (
|
|
133
|
+
f"DataSource(identifier={self.identifier}, "
|
|
134
|
+
f"data_provider_identifier={self.data_provider_identifier}, "
|
|
135
|
+
f"data_type={self.data_type}, symbol={self.symbol}, "
|
|
136
|
+
f"window_size={self.window_size}, time_frame={self.time_frame}, "
|
|
137
|
+
f"market={self.market}, storage_path={self.storage_path}, "
|
|
138
|
+
f"pandas={self.pandas}, date={self.date}, "
|
|
139
|
+
f"start_date={self.start_date}, end_date={self.end_date}, "
|
|
140
|
+
f"save={self.save})"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
def __eq__(self, other):
|
|
144
|
+
"""
|
|
145
|
+
Compares two DataSource instances for equality.
|
|
146
|
+
|
|
147
|
+
OHLCV data sources are considered equal if they have:
|
|
148
|
+
- The same data_type (OHLCV), symbol, time_frame, and market.
|
|
149
|
+
- If no market and timeframe is specified, then
|
|
150
|
+
they are considered equal for the same symbol
|
|
151
|
+
and data_type.
|
|
152
|
+
"""
|
|
153
|
+
if DataType.OHLCV.equals(self.data_type):
|
|
154
|
+
|
|
155
|
+
if other.time_frame is None and other.window_size is None:
|
|
156
|
+
return (self.data_type == other.data_type and
|
|
157
|
+
self.symbol == other.symbol)
|
|
158
|
+
elif self.time_frame is None and self.window_size is None:
|
|
159
|
+
return (self.data_type == other.data_type and
|
|
160
|
+
self.symbol == other.symbol)
|
|
161
|
+
|
|
162
|
+
return (self.time_frame == other.time_frame and
|
|
163
|
+
self.market == other.market and
|
|
164
|
+
self.symbol == other.symbol and
|
|
165
|
+
self.data_type == other.data_type)
|
|
166
|
+
|
|
167
|
+
elif DataType.CUSTOM.equals(self.data_type):
|
|
168
|
+
return (self.data_type == other.data_type and
|
|
169
|
+
self.symbol == other.symbol and
|
|
170
|
+
self.window_size == other.window_size and
|
|
171
|
+
self.time_frame == other.time_frame and
|
|
172
|
+
self.market == other.market)
|
|
173
|
+
|
|
174
|
+
elif DataType.TICKER.equals(self.data_type):
|
|
175
|
+
return (self.data_type == other.data_type and
|
|
176
|
+
self.symbol == other.symbol and
|
|
177
|
+
self.market == other.market)
|
|
178
|
+
|
|
179
|
+
return False
|
|
180
|
+
|
|
181
|
+
def create_start_date_data(self, index_date: datetime) -> datetime:
|
|
182
|
+
|
|
183
|
+
if self.window_size is None or self.time_frame is None:
|
|
184
|
+
return index_date
|
|
185
|
+
|
|
186
|
+
return index_date - \
|
|
187
|
+
(self.window_size * timedelta(
|
|
188
|
+
minutes=self.time_frame.amount_of_minutes
|
|
189
|
+
))
|
|
190
|
+
|
|
191
|
+
def get_number_of_required_data_points(
|
|
192
|
+
self, start_date: datetime, end_date: datetime
|
|
193
|
+
) -> int:
|
|
194
|
+
"""
|
|
195
|
+
Returns the number of data points required based on the given
|
|
196
|
+
attributes of the data source. If the required number of data points
|
|
197
|
+
can't be determined, it returns None.
|
|
198
|
+
|
|
199
|
+
E.g., for OHLCV data source, it
|
|
200
|
+
calculates the number of data points needed between the
|
|
201
|
+
start_date and end_date based on the time frame.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
start_date (datetime): The start date for the data points.
|
|
205
|
+
end_date (datetime): The end date for the data points.
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
int: The number of required data points, or None if it can't
|
|
209
|
+
be determined.
|
|
210
|
+
"""
|
|
211
|
+
|
|
212
|
+
if self.time_frame is None:
|
|
213
|
+
return None
|
|
214
|
+
|
|
215
|
+
delta = end_date - start_date
|
|
216
|
+
total_minutes = delta.total_seconds() / 60
|
|
217
|
+
data_points = total_minutes / self.time_frame.amount_of_minutes
|
|
218
|
+
|
|
219
|
+
if self.window_size is not None:
|
|
220
|
+
data_points += self.window_size
|
|
221
|
+
|
|
222
|
+
return int(data_points)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class DataType(Enum):
|
|
5
|
+
OHLCV = "OHLCV"
|
|
6
|
+
TICKER = "TICKER"
|
|
7
|
+
ORDER_BOOK = "ORDER_BOOK"
|
|
8
|
+
CUSTOM = "CUSTOM"
|
|
9
|
+
|
|
10
|
+
@staticmethod
|
|
11
|
+
def from_string(value: str):
|
|
12
|
+
|
|
13
|
+
if isinstance(value, str):
|
|
14
|
+
|
|
15
|
+
for entry in DataType:
|
|
16
|
+
|
|
17
|
+
if value.upper() == entry.value:
|
|
18
|
+
return entry
|
|
19
|
+
|
|
20
|
+
raise ValueError(
|
|
21
|
+
f"Could not convert {value} to DataType"
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def from_value(value):
|
|
26
|
+
|
|
27
|
+
if isinstance(value, str):
|
|
28
|
+
return DataType.from_string(value)
|
|
29
|
+
|
|
30
|
+
if isinstance(value, DataType):
|
|
31
|
+
|
|
32
|
+
for entry in DataType:
|
|
33
|
+
|
|
34
|
+
if value == entry:
|
|
35
|
+
return entry
|
|
36
|
+
|
|
37
|
+
raise ValueError(
|
|
38
|
+
f"Could not convert {value} to TimeFrame"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def equals(self, other):
|
|
42
|
+
|
|
43
|
+
if isinstance(other, Enum):
|
|
44
|
+
return self.value == other.value
|
|
45
|
+
else:
|
|
46
|
+
return DataType.from_string(other) == self
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Event(Enum):
|
|
5
|
+
PORTFOLIO_CREATED = "PORTFOLIO_CREATED"
|
|
6
|
+
ORDER_CREATED = "ORDER_CREATED"
|
|
7
|
+
TRADE_CLOSED = "TRADE_CLOSED"
|
|
8
|
+
STRATEGY_RUN = "STRATEGY_RUN"
|
|
9
|
+
|
|
10
|
+
@staticmethod
|
|
11
|
+
def from_string(value: str):
|
|
12
|
+
|
|
13
|
+
if isinstance(value, str):
|
|
14
|
+
for status in Event:
|
|
15
|
+
|
|
16
|
+
if value.upper() == status.value:
|
|
17
|
+
return status
|
|
18
|
+
|
|
19
|
+
raise ValueError("Could not convert value to Event")
|
|
20
|
+
|
|
21
|
+
@staticmethod
|
|
22
|
+
def from_value(value):
|
|
23
|
+
|
|
24
|
+
if isinstance(value, Event):
|
|
25
|
+
for status in Event:
|
|
26
|
+
|
|
27
|
+
if value == status:
|
|
28
|
+
return status
|
|
29
|
+
elif isinstance(value, str):
|
|
30
|
+
return Event.from_string(value)
|
|
31
|
+
|
|
32
|
+
raise ValueError(f"Could not convert value {value} to Event")
|
|
33
|
+
|
|
34
|
+
def equals(self, other):
|
|
35
|
+
return Event.from_value(other) == self
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
from investing_algorithm_framework.domain.exceptions import \
|
|
5
|
+
OperationalException
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger("investing_algorithm_framework")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MarketCredential:
|
|
11
|
+
"""
|
|
12
|
+
Market credential model to store the api key and secret key for a market.
|
|
13
|
+
"""
|
|
14
|
+
def __init__(
|
|
15
|
+
self, market: str, api_key: str = None, secret_key: str = None
|
|
16
|
+
):
|
|
17
|
+
self._api_key = api_key
|
|
18
|
+
self._secret_key = secret_key
|
|
19
|
+
self._market = market
|
|
20
|
+
|
|
21
|
+
def initialize(self):
|
|
22
|
+
"""
|
|
23
|
+
Internal helper to initialize the market credential.
|
|
24
|
+
"""
|
|
25
|
+
logger.info(f"Initializing market credential for {self.market}")
|
|
26
|
+
|
|
27
|
+
if self.api_key is None:
|
|
28
|
+
logger.info(
|
|
29
|
+
"Reading api key from environment variable"
|
|
30
|
+
f" {self.market.upper()}_API_KEY"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# Check if environment variable is set
|
|
34
|
+
environment_variable = f"{self.market.upper()}_API_KEY"
|
|
35
|
+
self._api_key = os.getenv(environment_variable)
|
|
36
|
+
|
|
37
|
+
if self.api_key is None:
|
|
38
|
+
raise OperationalException(
|
|
39
|
+
f"Market credential for market {self.market}"
|
|
40
|
+
" requires an api key, either"
|
|
41
|
+
" as an argument or as an environment variable"
|
|
42
|
+
f" named as {self._market.upper()}_API_KEY"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
if self.secret_key is None:
|
|
46
|
+
logger.info(
|
|
47
|
+
"Reading secret key from environment variable"
|
|
48
|
+
f" {self.market.upper()}_SECRET_KEY"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Check if environment variable is set
|
|
52
|
+
environment_variable = f"{self.market.upper()}_SECRET_KEY"
|
|
53
|
+
self._secret_key = os.getenv(environment_variable)
|
|
54
|
+
|
|
55
|
+
if self.api_key is not None:
|
|
56
|
+
self._api_key = self.api_key.strip()
|
|
57
|
+
|
|
58
|
+
if self.secret_key is not None:
|
|
59
|
+
self._secret_key = self.secret_key.strip()
|
|
60
|
+
|
|
61
|
+
def get_api_key(self):
|
|
62
|
+
return self.api_key
|
|
63
|
+
|
|
64
|
+
def get_secret_key(self):
|
|
65
|
+
return self.secret_key
|
|
66
|
+
|
|
67
|
+
def get_market(self):
|
|
68
|
+
return self.market
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def market(self):
|
|
72
|
+
return self._market
|
|
73
|
+
|
|
74
|
+
@market.setter
|
|
75
|
+
def market(self, market):
|
|
76
|
+
self._market = market
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def api_key(self):
|
|
80
|
+
return self._api_key
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def secret_key(self):
|
|
84
|
+
return self._secret_key
|
|
85
|
+
|
|
86
|
+
def __repr__(self):
|
|
87
|
+
return f"MarketCredential(" \
|
|
88
|
+
f"{self.market}, {self.api_key}, {self.secret_key}"
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
from .
|
|
1
|
+
from .order import Order
|
|
2
2
|
from .order_side import OrderSide
|
|
3
3
|
from .order_status import OrderStatus
|
|
4
|
-
from .
|
|
5
|
-
from .order_fee import OrderFee
|
|
4
|
+
from .order_type import OrderType
|
|
6
5
|
|
|
7
|
-
__all__ = ["OrderType", "OrderStatus", "OrderSide", "Order"
|
|
6
|
+
__all__ = ["OrderType", "OrderStatus", "OrderSide", "Order"]
|