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
|
@@ -1,410 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
from datetime import datetime
|
|
3
|
-
from time import sleep
|
|
4
|
-
|
|
5
|
-
import ccxt
|
|
6
|
-
|
|
7
|
-
from investing_algorithm_framework.domain import OperationalException, \
|
|
8
|
-
OHLCV, AssetPrice, Order, CCXT_DATETIME_FORMAT
|
|
9
|
-
|
|
10
|
-
logger = logging.getLogger("investing_algorithm_framework")
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class MarketService:
|
|
14
|
-
exchange = None
|
|
15
|
-
_market = None
|
|
16
|
-
api_key = None,
|
|
17
|
-
secret_key = None
|
|
18
|
-
exchange_class = None
|
|
19
|
-
msec = 1000
|
|
20
|
-
minute = 60 * msec
|
|
21
|
-
|
|
22
|
-
@property
|
|
23
|
-
def market(self):
|
|
24
|
-
return self._market
|
|
25
|
-
|
|
26
|
-
@market.setter
|
|
27
|
-
def market(self, value):
|
|
28
|
-
|
|
29
|
-
if not isinstance(value, str):
|
|
30
|
-
raise OperationalException("Market must be a string")
|
|
31
|
-
|
|
32
|
-
self._market = value.lower()
|
|
33
|
-
|
|
34
|
-
if not hasattr(ccxt, self._market):
|
|
35
|
-
raise OperationalException(
|
|
36
|
-
f"No market service found for market id {self._market}"
|
|
37
|
-
)
|
|
38
|
-
|
|
39
|
-
self.exchange_class = getattr(ccxt, self._market)
|
|
40
|
-
self.exchange = self.exchange_class()
|
|
41
|
-
|
|
42
|
-
def initialize(self, portfolio_configuration):
|
|
43
|
-
self.api_key = portfolio_configuration.api_key
|
|
44
|
-
self.secret_key = portfolio_configuration.secret_key
|
|
45
|
-
self._market = portfolio_configuration.market
|
|
46
|
-
|
|
47
|
-
if not hasattr(ccxt, self.market):
|
|
48
|
-
raise OperationalException(
|
|
49
|
-
f"No market service found for market id {self.market}"
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
self.exchange_class = getattr(ccxt, self.market)
|
|
53
|
-
|
|
54
|
-
if self.exchange_class is None:
|
|
55
|
-
raise OperationalException(
|
|
56
|
-
f"No market service found for market id {self.market}"
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
if self.api_key is not None or self.secret_key is not None:
|
|
60
|
-
self.exchange = self.exchange_class({
|
|
61
|
-
'apiKey': self.api_key,
|
|
62
|
-
'secret': self.secret_key,
|
|
63
|
-
})
|
|
64
|
-
else:
|
|
65
|
-
self.exchange = self.exchange_class({})
|
|
66
|
-
|
|
67
|
-
def pair_exists(self, target_symbol: str, trading_symbol: str):
|
|
68
|
-
|
|
69
|
-
if not self.exchange.has['fetchTicker']:
|
|
70
|
-
raise OperationalException(
|
|
71
|
-
f"Market service {self.market} does not support "
|
|
72
|
-
f"functionality pair_exists"
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
try:
|
|
76
|
-
data = self.get_ticker(f"{target_symbol}/{trading_symbol}")
|
|
77
|
-
return "symbol" in data
|
|
78
|
-
except OperationalException:
|
|
79
|
-
return False
|
|
80
|
-
|
|
81
|
-
def get_ticker(self, symbol):
|
|
82
|
-
|
|
83
|
-
if not self.exchange.has['fetchTicker']:
|
|
84
|
-
raise OperationalException(
|
|
85
|
-
f"Market service {self.market} does not support "
|
|
86
|
-
f"functionality get_ticker"
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
try:
|
|
90
|
-
return self.exchange.fetchTicker(symbol)
|
|
91
|
-
except Exception as e:
|
|
92
|
-
logger.exception(e)
|
|
93
|
-
raise OperationalException(
|
|
94
|
-
f"Could not retrieve ticker for symbol {symbol}"
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
def get_tickers(self, symbols):
|
|
98
|
-
|
|
99
|
-
if not self.exchange.has['fetchTickers']:
|
|
100
|
-
raise OperationalException(
|
|
101
|
-
f"Market service {self.market} does not support "
|
|
102
|
-
f"functionality get_tickers"
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
try:
|
|
106
|
-
return self.exchange.fetchTickers(symbols)
|
|
107
|
-
except Exception as e:
|
|
108
|
-
logger.exception(e)
|
|
109
|
-
raise OperationalException(
|
|
110
|
-
"Could not retrieve selection of tickers"
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
def get_order_book(self, symbol):
|
|
114
|
-
|
|
115
|
-
if not self.exchange.has['fetchOrderBook']:
|
|
116
|
-
raise OperationalException(
|
|
117
|
-
f"Market service {self.market} does not support "
|
|
118
|
-
f"functionality get_order_book"
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
try:
|
|
122
|
-
return self.exchange.fetchOrderBook(symbol)
|
|
123
|
-
except Exception as e:
|
|
124
|
-
logger.exception(e)
|
|
125
|
-
raise OperationalException("Could not retrieve order book")
|
|
126
|
-
|
|
127
|
-
def get_order_books(self, symbols):
|
|
128
|
-
data = {}
|
|
129
|
-
|
|
130
|
-
for symbol in symbols:
|
|
131
|
-
try:
|
|
132
|
-
entry = self.get_order_book(symbol)
|
|
133
|
-
del entry['symbol']
|
|
134
|
-
data[symbol] = entry
|
|
135
|
-
except Exception as e:
|
|
136
|
-
logger.exception(e)
|
|
137
|
-
|
|
138
|
-
return data
|
|
139
|
-
|
|
140
|
-
def get_order(self, order):
|
|
141
|
-
symbol = f"{order.target_symbol.upper()}/" \
|
|
142
|
-
f"{order.trading_symbol.upper()}"
|
|
143
|
-
|
|
144
|
-
if not self.exchange.has['fetchOrder']:
|
|
145
|
-
raise OperationalException(
|
|
146
|
-
f"Market service {self.market} does not support "
|
|
147
|
-
f"functionality get_order"
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
try:
|
|
151
|
-
order = self.exchange.fetchOrder(order.external_id, symbol)
|
|
152
|
-
return Order.from_ccxt_order(order)
|
|
153
|
-
except Exception as e:
|
|
154
|
-
logger.exception(e)
|
|
155
|
-
raise OperationalException("Could not retrieve order")
|
|
156
|
-
|
|
157
|
-
def get_orders(self, symbol, since: datetime = None):
|
|
158
|
-
|
|
159
|
-
if not self.exchange.has['fetchOrders']:
|
|
160
|
-
raise OperationalException(
|
|
161
|
-
f"Market service {self.market} does not support "
|
|
162
|
-
f"functionality get_orders"
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
if since is not None:
|
|
166
|
-
since = self.exchange.parse8601(
|
|
167
|
-
since.strftime(":%Y-%m-%d %H:%M:%S")
|
|
168
|
-
)
|
|
169
|
-
|
|
170
|
-
try:
|
|
171
|
-
ccxt_orders = self.exchange.fetchOrders(symbol, since=since)
|
|
172
|
-
return [Order.from_ccxt_order(order) for order in ccxt_orders]
|
|
173
|
-
except Exception as e:
|
|
174
|
-
logger.exception(e)
|
|
175
|
-
raise OperationalException("Could not retrieve orders")
|
|
176
|
-
else:
|
|
177
|
-
try:
|
|
178
|
-
ccxt_orders = self.exchange.fetchOrders(symbol)
|
|
179
|
-
return [Order.from_ccxt_order(order) for order in ccxt_orders]
|
|
180
|
-
except Exception as e:
|
|
181
|
-
logger.exception(e)
|
|
182
|
-
raise OperationalException("Could not retrieve orders")
|
|
183
|
-
|
|
184
|
-
def get_balance(self):
|
|
185
|
-
|
|
186
|
-
if not self.exchange.has['fetchBalance']:
|
|
187
|
-
raise OperationalException(
|
|
188
|
-
f"Market service {self.market} does not support "
|
|
189
|
-
f"functionality get_balance"
|
|
190
|
-
)
|
|
191
|
-
|
|
192
|
-
try:
|
|
193
|
-
return self.exchange.fetchBalance()
|
|
194
|
-
except Exception as e:
|
|
195
|
-
logger.exception(e)
|
|
196
|
-
raise OperationalException("Could not retrieve balance")
|
|
197
|
-
|
|
198
|
-
def create_limit_buy_order(
|
|
199
|
-
self,
|
|
200
|
-
target_symbol: str,
|
|
201
|
-
trading_symbol: str,
|
|
202
|
-
amount: float,
|
|
203
|
-
price: float
|
|
204
|
-
):
|
|
205
|
-
|
|
206
|
-
if not self.exchange.has['createLimitBuyOrder']:
|
|
207
|
-
raise OperationalException(
|
|
208
|
-
f"Market service {self.market} does not support "
|
|
209
|
-
f"functionality create_limit_buy_order"
|
|
210
|
-
)
|
|
211
|
-
|
|
212
|
-
symbol = f"{target_symbol.upper()}/{trading_symbol.upper()}"
|
|
213
|
-
|
|
214
|
-
try:
|
|
215
|
-
order = self.exchange.createLimitBuyOrder(
|
|
216
|
-
symbol, amount, price
|
|
217
|
-
)
|
|
218
|
-
return Order.from_ccxt_order(order)
|
|
219
|
-
except Exception as e:
|
|
220
|
-
logger.exception(e)
|
|
221
|
-
raise OperationalException("Could not create limit buy order")
|
|
222
|
-
|
|
223
|
-
def create_limit_sell_order(
|
|
224
|
-
self,
|
|
225
|
-
target_symbol: str,
|
|
226
|
-
trading_symbol: str,
|
|
227
|
-
amount: float,
|
|
228
|
-
price: float
|
|
229
|
-
):
|
|
230
|
-
|
|
231
|
-
if not self.exchange.has['createLimitSellOrder']:
|
|
232
|
-
raise OperationalException(
|
|
233
|
-
f"Market service {self.market} does not support "
|
|
234
|
-
f"functionality create_limit_sell_order"
|
|
235
|
-
)
|
|
236
|
-
|
|
237
|
-
symbol = f"{target_symbol.upper()}/{trading_symbol.upper()}"
|
|
238
|
-
|
|
239
|
-
try:
|
|
240
|
-
order = self.exchange.createLimitSellOrder(
|
|
241
|
-
symbol, amount, price
|
|
242
|
-
)
|
|
243
|
-
return Order.from_ccxt_order(order)
|
|
244
|
-
except Exception as e:
|
|
245
|
-
logger.exception(e)
|
|
246
|
-
raise OperationalException("Could not create limit sell order")
|
|
247
|
-
|
|
248
|
-
def create_market_sell_order(
|
|
249
|
-
self,
|
|
250
|
-
target_symbol: str,
|
|
251
|
-
trading_symbol: str,
|
|
252
|
-
amount: float,
|
|
253
|
-
):
|
|
254
|
-
|
|
255
|
-
if not self.exchange.has['createMarketSellOrder']:
|
|
256
|
-
raise OperationalException(
|
|
257
|
-
f"Market service {self.market} does not support "
|
|
258
|
-
f"functionality create_market_sell_order"
|
|
259
|
-
)
|
|
260
|
-
|
|
261
|
-
symbol = f"{target_symbol.upper()}/{trading_symbol.upper()}"
|
|
262
|
-
|
|
263
|
-
try:
|
|
264
|
-
order = self.exchange.createMarketSellOrder(symbol, amount)
|
|
265
|
-
return Order.from_ccxt_order(order)
|
|
266
|
-
except Exception as e:
|
|
267
|
-
logger.exception(e)
|
|
268
|
-
raise OperationalException("Could not create market sell order")
|
|
269
|
-
|
|
270
|
-
def cancel_order(self, order):
|
|
271
|
-
if not self.exchange.has['cancelOrder']:
|
|
272
|
-
raise OperationalException(
|
|
273
|
-
f"Market service {self.market} does not support "
|
|
274
|
-
f"functionality cancel_order"
|
|
275
|
-
)
|
|
276
|
-
|
|
277
|
-
self.exchange.cancelOrder(
|
|
278
|
-
order.get_order_reference(),
|
|
279
|
-
f"{order.get_target_symbol()}/{order.get_trading_symbol()}")
|
|
280
|
-
|
|
281
|
-
def get_open_orders(
|
|
282
|
-
self, target_symbol: str = None, trading_symbol: str = None
|
|
283
|
-
):
|
|
284
|
-
|
|
285
|
-
if not self.exchange.has['fetchOpenOrders']:
|
|
286
|
-
raise OperationalException(
|
|
287
|
-
f"Market service {self.market} does not support "
|
|
288
|
-
f"functionality get_open_orders"
|
|
289
|
-
)
|
|
290
|
-
|
|
291
|
-
try:
|
|
292
|
-
if target_symbol is None or trading_symbol is None:
|
|
293
|
-
return self.exchange.fetchOpenOrders()
|
|
294
|
-
|
|
295
|
-
symbol = f"{target_symbol.upper()}/{trading_symbol.upper()}"
|
|
296
|
-
ccxt_orders = self.exchange.fetchOpenOrders(symbol)
|
|
297
|
-
return [Order.from_ccxt_order(order) for order in ccxt_orders]
|
|
298
|
-
except Exception as e:
|
|
299
|
-
logger.exception(e)
|
|
300
|
-
raise OperationalException("Could not retrieve open orders")
|
|
301
|
-
|
|
302
|
-
def get_closed_orders(
|
|
303
|
-
self, target_symbol: str = None, trading_symbol: str = None
|
|
304
|
-
):
|
|
305
|
-
|
|
306
|
-
if not self.exchange.has['fetchClosedOrders']:
|
|
307
|
-
raise OperationalException(
|
|
308
|
-
f"Market service {self.market} does not support "
|
|
309
|
-
f"functionality get_closed_orders"
|
|
310
|
-
)
|
|
311
|
-
|
|
312
|
-
try:
|
|
313
|
-
if target_symbol is None or trading_symbol is None:
|
|
314
|
-
return self.exchange.fetchClosedOrders()
|
|
315
|
-
|
|
316
|
-
symbol = f"{target_symbol.upper()}/{trading_symbol.upper()}"
|
|
317
|
-
ccxt_orders = self.exchange.fetchClosedOrders(symbol)
|
|
318
|
-
return [Order.from_ccxt_order(order) for order in ccxt_orders]
|
|
319
|
-
except Exception as e:
|
|
320
|
-
logger.exception(e)
|
|
321
|
-
raise OperationalException("Could not retrieve closed orders")
|
|
322
|
-
|
|
323
|
-
def get_prices(self, symbols):
|
|
324
|
-
asset_prices = []
|
|
325
|
-
|
|
326
|
-
try:
|
|
327
|
-
tickers = self.exchange.fetchTickers(symbols)
|
|
328
|
-
for ticker in tickers:
|
|
329
|
-
asset_prices.append(
|
|
330
|
-
AssetPrice(
|
|
331
|
-
tickers[ticker]["symbol"],
|
|
332
|
-
tickers[ticker]["ask"],
|
|
333
|
-
tickers[ticker]["datetime"]
|
|
334
|
-
)
|
|
335
|
-
)
|
|
336
|
-
|
|
337
|
-
return asset_prices
|
|
338
|
-
except Exception as e:
|
|
339
|
-
logger.exception(e)
|
|
340
|
-
raise OperationalException("Could not retrieve prices")
|
|
341
|
-
|
|
342
|
-
def get_ohclv(self, symbol, time_frame, from_timestamp, to_timestamp=None):
|
|
343
|
-
|
|
344
|
-
if not self.exchange.has['fetchOHLCV']:
|
|
345
|
-
raise OperationalException(
|
|
346
|
-
f"Market service {self.market} does not support "
|
|
347
|
-
f"functionality get_ohclvs"
|
|
348
|
-
)
|
|
349
|
-
|
|
350
|
-
time_stamp = self.exchange.parse8601(
|
|
351
|
-
from_timestamp.strftime(CCXT_DATETIME_FORMAT)
|
|
352
|
-
)
|
|
353
|
-
|
|
354
|
-
if to_timestamp is None:
|
|
355
|
-
to_timestamp = self.exchange.milliseconds()
|
|
356
|
-
else:
|
|
357
|
-
to_timestamp = self.exchange.parse8601(
|
|
358
|
-
to_timestamp.strftime(CCXT_DATETIME_FORMAT)
|
|
359
|
-
)
|
|
360
|
-
data = []
|
|
361
|
-
|
|
362
|
-
while time_stamp < to_timestamp:
|
|
363
|
-
ohlcv = self.exchange.fetch_ohlcv(
|
|
364
|
-
symbol, time_frame.to_ccxt_string(), time_stamp
|
|
365
|
-
)
|
|
366
|
-
|
|
367
|
-
if len(ohlcv) > 0:
|
|
368
|
-
time_stamp = \
|
|
369
|
-
ohlcv[-1][0] + \
|
|
370
|
-
self.exchange.parse_timeframe(
|
|
371
|
-
time_frame.to_ccxt_string()
|
|
372
|
-
) * 1000
|
|
373
|
-
else:
|
|
374
|
-
time_stamp = to_timestamp
|
|
375
|
-
|
|
376
|
-
for candle in ohlcv:
|
|
377
|
-
datetime_stamp = datetime.strptime(
|
|
378
|
-
self.exchange.iso8601(candle[0]), CCXT_DATETIME_FORMAT
|
|
379
|
-
)
|
|
380
|
-
to_timestamp_datetime = datetime.strptime(
|
|
381
|
-
self.exchange.iso8601(to_timestamp), CCXT_DATETIME_FORMAT
|
|
382
|
-
)
|
|
383
|
-
|
|
384
|
-
if datetime_stamp < to_timestamp_datetime:
|
|
385
|
-
data.append([datetime_stamp] + candle[1:])
|
|
386
|
-
|
|
387
|
-
sleep(self.exchange.rateLimit / 1000)
|
|
388
|
-
|
|
389
|
-
return data
|
|
390
|
-
|
|
391
|
-
def get_ohclvs(
|
|
392
|
-
self,
|
|
393
|
-
symbols,
|
|
394
|
-
time_frame,
|
|
395
|
-
from_timestamp,
|
|
396
|
-
to_timestamp=None
|
|
397
|
-
):
|
|
398
|
-
ohlcvs = {}
|
|
399
|
-
|
|
400
|
-
for symbol in symbols:
|
|
401
|
-
|
|
402
|
-
try:
|
|
403
|
-
ohlcvs[symbol] = self.get_ohclv(
|
|
404
|
-
symbol, time_frame, from_timestamp, to_timestamp
|
|
405
|
-
)
|
|
406
|
-
except Exception as e:
|
|
407
|
-
logger.exception(e)
|
|
408
|
-
logger.error(f"Could not retrieve ohclv data for {symbol}")
|
|
409
|
-
|
|
410
|
-
return ohlcvs
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
from investing_algorithm_framework.domain import OrderStatus, OrderSide
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class PerformanceService:
|
|
5
|
-
|
|
6
|
-
def __init__(
|
|
7
|
-
self,
|
|
8
|
-
order_repository,
|
|
9
|
-
position_repository,
|
|
10
|
-
portfolio_repository,
|
|
11
|
-
):
|
|
12
|
-
self.order_repository = order_repository
|
|
13
|
-
self.position_repository = position_repository
|
|
14
|
-
self.portfolio_repository = portfolio_repository
|
|
15
|
-
|
|
16
|
-
def get_total_net_gain(self, portfolio_id):
|
|
17
|
-
pass
|
|
18
|
-
|
|
19
|
-
def get_total_size(self, portfolio_id):
|
|
20
|
-
pass
|
|
21
|
-
|
|
22
|
-
def get_percentage_change(self, portfolio_id, time_frame):
|
|
23
|
-
pass
|
|
24
|
-
|
|
25
|
-
def get_total_cost(self, portfolio_id):
|
|
26
|
-
pass
|
|
27
|
-
|
|
28
|
-
def get_number_of_trades_closed(self, portfolio_id):
|
|
29
|
-
portfolio = self.portfolio_repository.find({"id": portfolio_id})
|
|
30
|
-
number_of_trades_closed = 0
|
|
31
|
-
orders = self.order_repository.get_all(
|
|
32
|
-
{
|
|
33
|
-
"portfolio_id": portfolio.id,
|
|
34
|
-
"order_side": OrderSide.BUY.value,
|
|
35
|
-
}
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
for order in orders:
|
|
39
|
-
if order.get_trade_closed_at() is not None:
|
|
40
|
-
number_of_trades_closed += 1
|
|
41
|
-
|
|
42
|
-
return number_of_trades_closed
|
|
43
|
-
|
|
44
|
-
def get_number_of_trades_open(self, portfolio_id):
|
|
45
|
-
portfolio = self.portfolio_repository.find({"id": portfolio_id})
|
|
46
|
-
number_of_trades_open = 0
|
|
47
|
-
orders = self.order_repository.get_all(
|
|
48
|
-
{
|
|
49
|
-
"portfolio_id": portfolio.id,
|
|
50
|
-
"order_side": OrderSide.BUY.value,
|
|
51
|
-
}
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
for order in orders:
|
|
55
|
-
if order.get_trade_closed_at() is None:
|
|
56
|
-
number_of_trades_open += 1
|
|
57
|
-
|
|
58
|
-
return number_of_trades_open
|
|
59
|
-
|
|
60
|
-
def get_percentage_positive_trades(self, portfolio_id):
|
|
61
|
-
portfolio = self.portfolio_repository.find({"id": portfolio_id})
|
|
62
|
-
orders = self.order_repository.get_all(
|
|
63
|
-
{"portfolio_id": portfolio.id, "status": OrderStatus.CLOSED.value}
|
|
64
|
-
)
|
|
65
|
-
total_number_of_orders = len(orders)
|
|
66
|
-
|
|
67
|
-
if total_number_of_orders == 0:
|
|
68
|
-
return 0.0
|
|
69
|
-
|
|
70
|
-
positive_orders = [
|
|
71
|
-
order for order in orders if order.get_net_gain() > 0
|
|
72
|
-
]
|
|
73
|
-
total_number_of_positive_orders = len(positive_orders)
|
|
74
|
-
return total_number_of_positive_orders / total_number_of_orders * 100
|
|
75
|
-
|
|
76
|
-
def get_percentage_negative_trades(self, portfolio_id):
|
|
77
|
-
portfolio = self.portfolio_repository.find({"id": portfolio_id})
|
|
78
|
-
orders = self.order_repository.get_all(
|
|
79
|
-
{"portfolio_id": portfolio.id, "status": OrderStatus.CLOSED.value}
|
|
80
|
-
)
|
|
81
|
-
total_number_of_orders = len(orders)
|
|
82
|
-
|
|
83
|
-
if total_number_of_orders == 0:
|
|
84
|
-
return 0.0
|
|
85
|
-
|
|
86
|
-
negative_orders = [
|
|
87
|
-
order for order in orders if order.get_net_gain() < 0
|
|
88
|
-
]
|
|
89
|
-
total_number_of_negative_orders = len(negative_orders)
|
|
90
|
-
return total_number_of_negative_orders / total_number_of_orders * 100
|
|
91
|
-
|
|
92
|
-
def get_growth_rate_of_backtest(self, portfolio_id, tickers, backtest_profile):
|
|
93
|
-
portfolio = self.portfolio_repository.find({"id": portfolio_id})
|
|
94
|
-
positions = self.position_repository.get_all(
|
|
95
|
-
{"portfolio_id": portfolio.id}
|
|
96
|
-
)
|
|
97
|
-
allocated = 0
|
|
98
|
-
|
|
99
|
-
for position in positions:
|
|
100
|
-
|
|
101
|
-
if position.symbol == portfolio.trading_symbol:
|
|
102
|
-
continue
|
|
103
|
-
|
|
104
|
-
allocated += position.amount * tickers[position.symbol]["bid"]
|
|
105
|
-
|
|
106
|
-
current_total_value = allocated + portfolio.unallocated
|
|
107
|
-
gain = current_total_value - backtest_profile.initial_unallocated
|
|
108
|
-
return gain / backtest_profile.initial_unallocated * 100
|
|
109
|
-
|
|
110
|
-
def get_growth_of_backtest(self, portfolio_id, tickers, backtest_profile):
|
|
111
|
-
portfolio = self.portfolio_repository.find({"id": portfolio_id})
|
|
112
|
-
positions = self.position_repository.get_all(
|
|
113
|
-
{"portfolio_id": portfolio.id}
|
|
114
|
-
)
|
|
115
|
-
allocated = 0
|
|
116
|
-
|
|
117
|
-
for position in positions:
|
|
118
|
-
|
|
119
|
-
if position.symbol == portfolio.trading_symbol:
|
|
120
|
-
continue
|
|
121
|
-
|
|
122
|
-
allocated += position.amount * tickers[position.symbol]["bid"]
|
|
123
|
-
|
|
124
|
-
current_total_value = allocated + portfolio.unallocated
|
|
125
|
-
return current_total_value - backtest_profile.initial_unallocated
|
|
126
|
-
|
|
127
|
-
def get_total_net_gain_percentage_of_backtest(self, portfolio_id, backtest_profile):
|
|
128
|
-
portfolio = self.portfolio_repository.find({"id": portfolio_id})
|
|
129
|
-
return portfolio.total_net_gain \
|
|
130
|
-
/ backtest_profile.initial_unallocated * 100
|
|
131
|
-
|
|
132
|
-
def get_total_value(self, portfolio_id, tickers, backtest_profile):
|
|
133
|
-
portfolio = self.portfolio_repository.find({"id": portfolio_id})
|
|
134
|
-
positions = self.position_repository.get_all(
|
|
135
|
-
{"portfolio_id": portfolio.id}
|
|
136
|
-
)
|
|
137
|
-
allocated = 0
|
|
138
|
-
|
|
139
|
-
for position in positions:
|
|
140
|
-
|
|
141
|
-
if position.symbol == portfolio.trading_symbol:
|
|
142
|
-
continue
|
|
143
|
-
|
|
144
|
-
allocated += position.amount * tickers[position.symbol]["bid"]
|
|
145
|
-
|
|
146
|
-
return allocated + portfolio.unallocated
|
|
147
|
-
|
|
148
|
-
def get_average_trade_duration(self, portfolio_id):
|
|
149
|
-
portfolio = self.portfolio_repository.find({"id": portfolio_id})
|
|
150
|
-
buy_orders = self.order_repository.get_all(
|
|
151
|
-
{
|
|
152
|
-
"portfolio_id": portfolio.id,
|
|
153
|
-
"order_side": OrderSide.BUY.value,
|
|
154
|
-
}
|
|
155
|
-
)
|
|
156
|
-
buy_orders_with_trade_closed = [
|
|
157
|
-
order for order in buy_orders if order.get_trade_closed_at() != None
|
|
158
|
-
]
|
|
159
|
-
|
|
160
|
-
if len(buy_orders_with_trade_closed) == 0:
|
|
161
|
-
return 0
|
|
162
|
-
|
|
163
|
-
total_duration = 0
|
|
164
|
-
|
|
165
|
-
for order in buy_orders_with_trade_closed:
|
|
166
|
-
duration = order.get_trade_closed_at() - order.get_created_at()
|
|
167
|
-
total_duration += duration.total_seconds() / 3600
|
|
168
|
-
|
|
169
|
-
return total_duration / len(buy_orders_with_trade_closed)
|
|
170
|
-
|
|
171
|
-
def get_average_trade_size(self, portfolio_id):
|
|
172
|
-
portfolio = self.portfolio_repository.find({"id": portfolio_id})
|
|
173
|
-
buy_orders = self.order_repository.get_all(
|
|
174
|
-
{
|
|
175
|
-
"portfolio_id": portfolio.id,
|
|
176
|
-
"order_side": OrderSide.BUY.value,
|
|
177
|
-
}
|
|
178
|
-
)
|
|
179
|
-
closed_buy_orders = [
|
|
180
|
-
order for order in buy_orders
|
|
181
|
-
if order.get_trade_closed_at() != None
|
|
182
|
-
]
|
|
183
|
-
|
|
184
|
-
if len(closed_buy_orders) == 0:
|
|
185
|
-
return 0
|
|
186
|
-
|
|
187
|
-
total_size = 0
|
|
188
|
-
|
|
189
|
-
for order in closed_buy_orders:
|
|
190
|
-
total_size += order.get_amount() * order.get_price()
|
|
191
|
-
|
|
192
|
-
return total_size / len(closed_buy_orders)
|