investing-algorithm-framework 6.9.1__py3-none-any.whl → 7.19.15__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of investing-algorithm-framework might be problematic. Click here for more details.
- investing_algorithm_framework/__init__.py +147 -44
- investing_algorithm_framework/app/__init__.py +23 -6
- investing_algorithm_framework/app/algorithm/algorithm.py +5 -41
- investing_algorithm_framework/app/algorithm/algorithm_factory.py +17 -10
- investing_algorithm_framework/app/analysis/__init__.py +15 -0
- investing_algorithm_framework/app/analysis/backtest_data_ranges.py +121 -0
- investing_algorithm_framework/app/analysis/backtest_utils.py +107 -0
- investing_algorithm_framework/app/analysis/permutation.py +116 -0
- investing_algorithm_framework/app/analysis/ranking.py +297 -0
- investing_algorithm_framework/app/app.py +1322 -707
- investing_algorithm_framework/app/context.py +196 -88
- investing_algorithm_framework/app/eventloop.py +590 -0
- investing_algorithm_framework/app/reporting/__init__.py +16 -5
- investing_algorithm_framework/app/reporting/ascii.py +57 -202
- investing_algorithm_framework/app/reporting/backtest_report.py +284 -170
- investing_algorithm_framework/app/reporting/charts/__init__.py +10 -2
- 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 +11 -26
- investing_algorithm_framework/app/reporting/charts/line_chart.py +11 -0
- investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +51 -0
- investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +1 -1
- investing_algorithm_framework/app/reporting/generate.py +100 -114
- investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +40 -32
- investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +34 -27
- investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +23 -19
- investing_algorithm_framework/app/reporting/tables/trades_table.py +1 -1
- investing_algorithm_framework/app/reporting/tables/utils.py +1 -0
- investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +10 -16
- investing_algorithm_framework/app/strategy.py +315 -175
- investing_algorithm_framework/app/task.py +5 -3
- investing_algorithm_framework/cli/cli.py +30 -12
- investing_algorithm_framework/cli/deploy_to_aws_lambda.py +131 -34
- investing_algorithm_framework/cli/initialize_app.py +20 -1
- investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +18 -6
- 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_requirements.txt.template +2 -2
- investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +1 -1
- investing_algorithm_framework/create_app.py +3 -5
- investing_algorithm_framework/dependency_container.py +25 -39
- investing_algorithm_framework/domain/__init__.py +45 -38
- investing_algorithm_framework/domain/backtesting/__init__.py +21 -0
- investing_algorithm_framework/domain/backtesting/backtest.py +503 -0
- investing_algorithm_framework/domain/backtesting/backtest_date_range.py +96 -0
- investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +242 -0
- investing_algorithm_framework/domain/backtesting/backtest_metrics.py +459 -0
- investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +275 -0
- investing_algorithm_framework/domain/backtesting/backtest_run.py +605 -0
- investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +162 -0
- investing_algorithm_framework/domain/backtesting/combine_backtests.py +280 -0
- investing_algorithm_framework/domain/config.py +27 -0
- investing_algorithm_framework/domain/constants.py +6 -34
- investing_algorithm_framework/domain/data_provider.py +200 -56
- investing_algorithm_framework/domain/exceptions.py +34 -1
- investing_algorithm_framework/domain/models/__init__.py +10 -19
- investing_algorithm_framework/domain/models/base_model.py +0 -6
- investing_algorithm_framework/domain/models/data/__init__.py +7 -0
- investing_algorithm_framework/domain/models/data/data_source.py +214 -0
- investing_algorithm_framework/domain/models/{market_data_type.py → data/data_type.py} +7 -7
- investing_algorithm_framework/domain/models/market/market_credential.py +6 -0
- investing_algorithm_framework/domain/models/order/order.py +34 -13
- investing_algorithm_framework/domain/models/order/order_status.py +1 -1
- investing_algorithm_framework/domain/models/order/order_type.py +1 -1
- investing_algorithm_framework/domain/models/portfolio/portfolio.py +14 -1
- investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +5 -1
- investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +51 -11
- investing_algorithm_framework/domain/models/position/__init__.py +2 -1
- investing_algorithm_framework/domain/models/position/position.py +9 -0
- investing_algorithm_framework/domain/models/position/position_size.py +41 -0
- investing_algorithm_framework/domain/models/risk_rules/__init__.py +7 -0
- investing_algorithm_framework/domain/models/risk_rules/stop_loss_rule.py +51 -0
- investing_algorithm_framework/domain/models/risk_rules/take_profit_rule.py +55 -0
- investing_algorithm_framework/domain/models/snapshot_interval.py +0 -1
- investing_algorithm_framework/domain/models/strategy_profile.py +19 -151
- investing_algorithm_framework/domain/models/time_frame.py +7 -0
- investing_algorithm_framework/domain/models/time_interval.py +33 -0
- investing_algorithm_framework/domain/models/time_unit.py +63 -1
- investing_algorithm_framework/domain/models/trade/__init__.py +0 -2
- investing_algorithm_framework/domain/models/trade/trade.py +56 -32
- investing_algorithm_framework/domain/models/trade/trade_status.py +8 -2
- investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +106 -41
- investing_algorithm_framework/domain/models/trade/trade_take_profit.py +161 -99
- investing_algorithm_framework/domain/order_executor.py +19 -0
- investing_algorithm_framework/domain/portfolio_provider.py +20 -1
- investing_algorithm_framework/domain/services/__init__.py +0 -13
- investing_algorithm_framework/domain/strategy.py +1 -29
- investing_algorithm_framework/domain/utils/__init__.py +5 -1
- investing_algorithm_framework/domain/utils/custom_tqdm.py +22 -0
- investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +19 -0
- investing_algorithm_framework/domain/utils/polars.py +17 -14
- investing_algorithm_framework/download_data.py +40 -10
- investing_algorithm_framework/infrastructure/__init__.py +13 -25
- investing_algorithm_framework/infrastructure/data_providers/__init__.py +7 -4
- investing_algorithm_framework/infrastructure/data_providers/ccxt.py +811 -546
- investing_algorithm_framework/infrastructure/data_providers/csv.py +433 -122
- 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 +81 -0
- investing_algorithm_framework/infrastructure/models/__init__.py +0 -13
- investing_algorithm_framework/infrastructure/models/order/order.py +9 -3
- investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +27 -8
- investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +21 -7
- investing_algorithm_framework/infrastructure/order_executors/__init__.py +2 -0
- investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +28 -0
- investing_algorithm_framework/infrastructure/repositories/repository.py +16 -2
- investing_algorithm_framework/infrastructure/repositories/trade_repository.py +2 -2
- investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +6 -0
- investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +6 -0
- investing_algorithm_framework/infrastructure/services/__init__.py +0 -4
- investing_algorithm_framework/services/__init__.py +105 -8
- investing_algorithm_framework/services/backtesting/backtest_service.py +536 -476
- investing_algorithm_framework/services/configuration_service.py +14 -4
- investing_algorithm_framework/services/data_providers/__init__.py +5 -0
- investing_algorithm_framework/services/data_providers/data_provider_service.py +850 -0
- investing_algorithm_framework/{app/reporting → services}/metrics/__init__.py +48 -17
- investing_algorithm_framework/{app/reporting → services}/metrics/drawdown.py +10 -10
- investing_algorithm_framework/{app/reporting → services}/metrics/equity_curve.py +2 -2
- investing_algorithm_framework/{app/reporting → services}/metrics/exposure.py +60 -2
- investing_algorithm_framework/services/metrics/generate.py +358 -0
- investing_algorithm_framework/{app/reporting → services}/metrics/profit_factor.py +36 -0
- investing_algorithm_framework/{app/reporting → services}/metrics/recovery.py +2 -2
- investing_algorithm_framework/{app/reporting → services}/metrics/returns.py +146 -147
- investing_algorithm_framework/services/metrics/risk_free_rate.py +28 -0
- investing_algorithm_framework/{app/reporting/metrics/sharp_ratio.py → services/metrics/sharpe_ratio.py} +6 -10
- investing_algorithm_framework/{app/reporting → services}/metrics/sortino_ratio.py +3 -7
- investing_algorithm_framework/services/metrics/trades.py +500 -0
- investing_algorithm_framework/services/metrics/volatility.py +97 -0
- investing_algorithm_framework/{app/reporting → services}/metrics/win_rate.py +70 -3
- investing_algorithm_framework/services/order_service/order_backtest_service.py +21 -31
- investing_algorithm_framework/services/order_service/order_service.py +9 -71
- investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +0 -2
- investing_algorithm_framework/services/portfolios/portfolio_service.py +3 -13
- investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +62 -96
- investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +0 -3
- investing_algorithm_framework/services/repository_service.py +5 -2
- investing_algorithm_framework/services/trade_order_evaluator/__init__.py +9 -0
- investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +113 -0
- investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +51 -0
- investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +80 -0
- investing_algorithm_framework/services/trade_service/__init__.py +7 -1
- investing_algorithm_framework/services/trade_service/trade_service.py +51 -29
- investing_algorithm_framework/services/trade_service/trade_stop_loss_service.py +39 -0
- investing_algorithm_framework/services/trade_service/trade_take_profit_service.py +41 -0
- investing_algorithm_framework-7.19.15.dist-info/METADATA +537 -0
- {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/RECORD +159 -148
- investing_algorithm_framework/app/reporting/evaluation.py +0 -243
- investing_algorithm_framework/app/reporting/metrics/risk_free_rate.py +0 -8
- investing_algorithm_framework/app/reporting/metrics/volatility.py +0 -69
- investing_algorithm_framework/cli/templates/requirements_azure_function.txt.template +0 -3
- investing_algorithm_framework/domain/models/backtesting/__init__.py +0 -9
- investing_algorithm_framework/domain/models/backtesting/backtest_date_range.py +0 -47
- investing_algorithm_framework/domain/models/backtesting/backtest_position.py +0 -120
- investing_algorithm_framework/domain/models/backtesting/backtest_reports_evaluation.py +0 -0
- investing_algorithm_framework/domain/models/backtesting/backtest_results.py +0 -440
- investing_algorithm_framework/domain/models/data_source.py +0 -21
- investing_algorithm_framework/domain/models/date_range.py +0 -64
- investing_algorithm_framework/domain/models/trade/trade_risk_type.py +0 -34
- investing_algorithm_framework/domain/models/trading_data_types.py +0 -48
- investing_algorithm_framework/domain/models/trading_time_frame.py +0 -223
- investing_algorithm_framework/domain/services/market_data_sources.py +0 -543
- investing_algorithm_framework/domain/services/market_service.py +0 -153
- investing_algorithm_framework/domain/services/observable.py +0 -51
- investing_algorithm_framework/domain/services/observer.py +0 -19
- investing_algorithm_framework/infrastructure/models/market_data_sources/__init__.py +0 -16
- investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py +0 -746
- investing_algorithm_framework/infrastructure/models/market_data_sources/csv.py +0 -270
- investing_algorithm_framework/infrastructure/models/market_data_sources/pandas.py +0 -312
- investing_algorithm_framework/infrastructure/services/market_service/__init__.py +0 -5
- investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py +0 -471
- investing_algorithm_framework/infrastructure/services/performance_service/__init__.py +0 -7
- investing_algorithm_framework/infrastructure/services/performance_service/backtest_performance_service.py +0 -2
- investing_algorithm_framework/infrastructure/services/performance_service/performance_service.py +0 -322
- investing_algorithm_framework/services/market_data_source_service/__init__.py +0 -10
- investing_algorithm_framework/services/market_data_source_service/backtest_market_data_source_service.py +0 -269
- investing_algorithm_framework/services/market_data_source_service/data_provider_service.py +0 -350
- investing_algorithm_framework/services/market_data_source_service/market_data_source_service.py +0 -377
- investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -296
- investing_algorithm_framework-6.9.1.dist-info/METADATA +0 -440
- /investing_algorithm_framework/{app/reporting → services}/metrics/alpha.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/beta.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/cagr.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/calmar_ratio.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/mean_daily_return.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/price_efficiency.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/standard_deviation.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/treynor_ratio.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/ulcer.py +0 -0
- /investing_algorithm_framework/{app/reporting → services}/metrics/value_at_risk.py +0 -0
- {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/LICENSE +0 -0
- {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/WHEEL +0 -0
- {investing_algorithm_framework-6.9.1.dist-info → investing_algorithm_framework-7.19.15.dist-info}/entry_points.txt +0 -0
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
from datetime import datetime, timezone
|
|
2
3
|
from typing import List
|
|
3
4
|
|
|
4
5
|
from investing_algorithm_framework.services import ConfigurationService, \
|
|
5
|
-
MarketCredentialService,
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
MarketCredentialService, OrderService, PortfolioConfigurationService, \
|
|
7
|
+
PortfolioService, PositionService, TradeService, DataProviderService, \
|
|
8
|
+
TradeStopLossService, TradeTakeProfitService
|
|
8
9
|
from investing_algorithm_framework.domain import OrderStatus, OrderType, \
|
|
9
10
|
OrderSide, OperationalException, Portfolio, RoundingService, \
|
|
10
|
-
BACKTESTING_FLAG,
|
|
11
|
-
Position, Trade, TradeStatus,
|
|
11
|
+
BACKTESTING_FLAG, INDEX_DATETIME, Order, \
|
|
12
|
+
Position, Trade, TradeStatus, MarketCredential, TradeStopLoss, \
|
|
13
|
+
TradeTakeProfit
|
|
12
14
|
|
|
13
15
|
logger = logging.getLogger("investing_algorithm_framework")
|
|
14
16
|
|
|
@@ -28,9 +30,10 @@ class Context:
|
|
|
28
30
|
position_service: PositionService,
|
|
29
31
|
order_service: OrderService,
|
|
30
32
|
market_credential_service: MarketCredentialService,
|
|
31
|
-
market_data_source_service: MarketDataSourceService,
|
|
32
|
-
market_service: MarketService,
|
|
33
33
|
trade_service: TradeService,
|
|
34
|
+
trade_stop_loss_service: TradeStopLossService,
|
|
35
|
+
trade_take_profit_service: TradeTakeProfitService,
|
|
36
|
+
data_provider_service: DataProviderService
|
|
34
37
|
):
|
|
35
38
|
self.configuration_service: ConfigurationService = \
|
|
36
39
|
configuration_service
|
|
@@ -41,10 +44,12 @@ class Context:
|
|
|
41
44
|
self.order_service: OrderService = order_service
|
|
42
45
|
self.market_credential_service: MarketCredentialService = \
|
|
43
46
|
market_credential_service
|
|
44
|
-
self.
|
|
45
|
-
market_data_source_service
|
|
46
|
-
self.market_service: MarketService = market_service
|
|
47
|
+
self.data_provider_service: DataProviderService = data_provider_service
|
|
47
48
|
self.trade_service: TradeService = trade_service
|
|
49
|
+
self.trade_stop_loss_service: TradeStopLossService = \
|
|
50
|
+
trade_stop_loss_service
|
|
51
|
+
self.trade_take_profit_service: TradeTakeProfitService = \
|
|
52
|
+
trade_take_profit_service
|
|
48
53
|
|
|
49
54
|
@property
|
|
50
55
|
def config(self):
|
|
@@ -110,7 +115,7 @@ class Context:
|
|
|
110
115
|
if BACKTESTING_FLAG in self.configuration_service.config \
|
|
111
116
|
and self.configuration_service.config[BACKTESTING_FLAG]:
|
|
112
117
|
order_data["created_at"] = \
|
|
113
|
-
self.configuration_service.config[
|
|
118
|
+
self.configuration_service.config[INDEX_DATETIME]
|
|
114
119
|
|
|
115
120
|
return self.order_service.create(
|
|
116
121
|
order_data, execute=execute, validate=validate, sync=sync
|
|
@@ -255,7 +260,7 @@ class Context:
|
|
|
255
260
|
if BACKTESTING_FLAG in self.configuration_service.config \
|
|
256
261
|
and self.configuration_service.config[BACKTESTING_FLAG]:
|
|
257
262
|
order_data["created_at"] = \
|
|
258
|
-
self.configuration_service.config[
|
|
263
|
+
self.configuration_service.config[INDEX_DATETIME]
|
|
259
264
|
|
|
260
265
|
return self.order_service.create(
|
|
261
266
|
order_data, execute=execute, validate=validate, sync=sync
|
|
@@ -333,7 +338,7 @@ class Context:
|
|
|
333
338
|
if BACKTESTING_FLAG in self.configuration_service.config \
|
|
334
339
|
and self.configuration_service.config[BACKTESTING_FLAG]:
|
|
335
340
|
order_data["created_at"] = \
|
|
336
|
-
self.configuration_service.config[
|
|
341
|
+
self.configuration_service.config[INDEX_DATETIME]
|
|
337
342
|
|
|
338
343
|
return self.order_service.create(order_data)
|
|
339
344
|
|
|
@@ -404,7 +409,7 @@ class Context:
|
|
|
404
409
|
if BACKTESTING_FLAG in self.configuration_service.config \
|
|
405
410
|
and self.configuration_service.config[BACKTESTING_FLAG]:
|
|
406
411
|
order_data["created_at"] = \
|
|
407
|
-
self.configuration_service.config[
|
|
412
|
+
self.configuration_service.config[INDEX_DATETIME]
|
|
408
413
|
return self.order_service.create(
|
|
409
414
|
order_data, execute=True, validate=True, sync=True
|
|
410
415
|
)
|
|
@@ -424,9 +429,52 @@ class Context:
|
|
|
424
429
|
"""
|
|
425
430
|
|
|
426
431
|
if market is None:
|
|
427
|
-
|
|
432
|
+
portfolio = self.portfolio_service.get_all()[0]
|
|
433
|
+
else:
|
|
434
|
+
portfolio = self.portfolio_service.find({"market": market})
|
|
435
|
+
|
|
436
|
+
# Retrieve positions
|
|
437
|
+
positions = self.position_service.get_all(
|
|
438
|
+
{"portfolio": portfolio.id}
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
if BACKTESTING_FLAG in self.configuration_service.config \
|
|
442
|
+
and self.configuration_service.config[BACKTESTING_FLAG]:
|
|
443
|
+
date = self.configuration_service.config[INDEX_DATETIME]
|
|
444
|
+
else:
|
|
445
|
+
date = datetime.now(tz=timezone.utc)
|
|
446
|
+
|
|
447
|
+
allocated = 0.0
|
|
448
|
+
|
|
449
|
+
for position in positions:
|
|
450
|
+
|
|
451
|
+
if position.symbol != portfolio.trading_symbol:
|
|
452
|
+
ticker = self.data_provider_service.get_ticker_data(
|
|
453
|
+
symbol=f"{position.symbol}/{portfolio.trading_symbol}",
|
|
454
|
+
market=portfolio.market,
|
|
455
|
+
date=date
|
|
456
|
+
)
|
|
457
|
+
if ticker is not None and "bid" in ticker:
|
|
458
|
+
allocated += position.get_amount() * ticker["bid"]
|
|
459
|
+
|
|
460
|
+
portfolio.allocated = allocated
|
|
461
|
+
return portfolio
|
|
462
|
+
|
|
463
|
+
def get_latest_price(self, symbol, market=None):
|
|
464
|
+
|
|
465
|
+
if BACKTESTING_FLAG in self.configuration_service.config \
|
|
466
|
+
and self.configuration_service.config[BACKTESTING_FLAG]:
|
|
467
|
+
date = self.configuration_service.config[INDEX_DATETIME]
|
|
468
|
+
else:
|
|
469
|
+
date = datetime.now(tz=timezone.utc)
|
|
470
|
+
|
|
471
|
+
ticker = self.data_provider_service.get_ticker_data(
|
|
472
|
+
symbol=symbol,
|
|
473
|
+
market=market,
|
|
474
|
+
date=date
|
|
475
|
+
)
|
|
428
476
|
|
|
429
|
-
return
|
|
477
|
+
return ticker['bid'] if ticker and 'bid' in ticker else None
|
|
430
478
|
|
|
431
479
|
def get_portfolios(self):
|
|
432
480
|
"""
|
|
@@ -761,41 +809,6 @@ class Context:
|
|
|
761
809
|
query_params["symbol"] = symbol
|
|
762
810
|
return self.position_service.exists(query_params)
|
|
763
811
|
|
|
764
|
-
def get_position_percentage_of_portfolio(
|
|
765
|
-
self, symbol, market=None, identifier=None
|
|
766
|
-
) -> float:
|
|
767
|
-
"""
|
|
768
|
-
Returns the percentage of the current total value of the portfolio
|
|
769
|
-
that is allocated to a position. This is calculated by dividing
|
|
770
|
-
the current value of the position by the total current value
|
|
771
|
-
of the portfolio.
|
|
772
|
-
"""
|
|
773
|
-
|
|
774
|
-
query_params = {}
|
|
775
|
-
|
|
776
|
-
if market is not None:
|
|
777
|
-
query_params["market"] = market
|
|
778
|
-
|
|
779
|
-
if identifier is not None:
|
|
780
|
-
query_params["identifier"] = identifier
|
|
781
|
-
|
|
782
|
-
portfolios = self.portfolio_service.get_all(query_params)
|
|
783
|
-
|
|
784
|
-
if not portfolios:
|
|
785
|
-
raise OperationalException("No portfolio found.")
|
|
786
|
-
|
|
787
|
-
portfolio = portfolios[0]
|
|
788
|
-
position = self.position_service.find(
|
|
789
|
-
{"portfolio": portfolio.id, "symbol": symbol}
|
|
790
|
-
)
|
|
791
|
-
full_symbol = f"{position.symbol.upper()}/" \
|
|
792
|
-
f"{portfolio.trading_symbol.upper()}"
|
|
793
|
-
ticker = self.market_data_source_service.get_ticker(
|
|
794
|
-
symbol=full_symbol, market=market
|
|
795
|
-
)
|
|
796
|
-
total = self.get_unallocated() + self.get_allocated()
|
|
797
|
-
return (position.amount * ticker["bid"] / total) * 100
|
|
798
|
-
|
|
799
812
|
def get_position_percentage_of_portfolio_by_net_size(
|
|
800
813
|
self, symbol, market=None, identifier=None
|
|
801
814
|
) -> float:
|
|
@@ -828,7 +841,12 @@ class Context:
|
|
|
828
841
|
return (position.cost / net_size) * 100
|
|
829
842
|
|
|
830
843
|
def close_position(
|
|
831
|
-
self,
|
|
844
|
+
self,
|
|
845
|
+
position=None,
|
|
846
|
+
symbol=None,
|
|
847
|
+
portfolio=None,
|
|
848
|
+
precision=None,
|
|
849
|
+
price=None
|
|
832
850
|
) -> Order:
|
|
833
851
|
"""
|
|
834
852
|
Function to close a position. This function will close a position
|
|
@@ -841,6 +859,8 @@ class Context:
|
|
|
841
859
|
symbol (Optional): The symbol of the asset
|
|
842
860
|
portfolio (Optional): The portfolio where the position is located
|
|
843
861
|
precision (Optional): The precision of the amount
|
|
862
|
+
price (Optional[Float]): The price with which the position needs
|
|
863
|
+
to be closed.
|
|
844
864
|
|
|
845
865
|
Returns:
|
|
846
866
|
Order: The order created to close the position
|
|
@@ -887,19 +907,25 @@ class Context:
|
|
|
887
907
|
|
|
888
908
|
target_symbol = position.get_symbol()
|
|
889
909
|
symbol = f"{target_symbol.upper()}/{portfolio.trading_symbol.upper()}"
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
910
|
+
|
|
911
|
+
if price is None:
|
|
912
|
+
ticker = self.data_provider_service.get_ticker_data(
|
|
913
|
+
symbol=symbol,
|
|
914
|
+
market=portfolio.market,
|
|
915
|
+
date=self.config[INDEX_DATETIME]
|
|
916
|
+
)
|
|
917
|
+
price = ticker["bid"]
|
|
918
|
+
|
|
893
919
|
logger.info(
|
|
894
920
|
f"Closing position {position.symbol} "
|
|
895
921
|
f"with amount {position.get_amount()} "
|
|
896
|
-
f"at price {
|
|
922
|
+
f"at price {price}"
|
|
897
923
|
)
|
|
898
924
|
return self.create_limit_order(
|
|
899
925
|
target_symbol=position.symbol,
|
|
900
926
|
amount=position.get_amount(),
|
|
901
927
|
order_side=OrderSide.SELL.value,
|
|
902
|
-
price=
|
|
928
|
+
price=price,
|
|
903
929
|
precision=precision,
|
|
904
930
|
)
|
|
905
931
|
|
|
@@ -951,8 +977,9 @@ class Context:
|
|
|
951
977
|
|
|
952
978
|
symbol = f"{position.symbol.upper()}/" \
|
|
953
979
|
f"{portfolio.trading_symbol.upper()}"
|
|
954
|
-
|
|
955
|
-
|
|
980
|
+
current_date = self.config[INDEX_DATETIME]
|
|
981
|
+
ticker = self.data_provider_service.get_ticker_data(
|
|
982
|
+
symbol=symbol, market=portfolio.market, date=current_date
|
|
956
983
|
)
|
|
957
984
|
allocated = allocated + \
|
|
958
985
|
(position.get_amount() * ticker["bid"])
|
|
@@ -1351,11 +1378,12 @@ class Context:
|
|
|
1351
1378
|
|
|
1352
1379
|
def add_stop_loss(
|
|
1353
1380
|
self,
|
|
1354
|
-
trade,
|
|
1381
|
+
trade: Trade,
|
|
1355
1382
|
percentage: float,
|
|
1356
|
-
|
|
1383
|
+
trailing: bool = False,
|
|
1357
1384
|
sell_percentage: float = 100,
|
|
1358
|
-
|
|
1385
|
+
created_at: datetime = None,
|
|
1386
|
+
) -> TradeStopLoss:
|
|
1359
1387
|
"""
|
|
1360
1388
|
Function to add a stop loss to a trade.
|
|
1361
1389
|
|
|
@@ -1373,32 +1401,39 @@ class Context:
|
|
|
1373
1401
|
* BTC price drops to $39,900 → SL level reached, trade closes.
|
|
1374
1402
|
|
|
1375
1403
|
Args:
|
|
1376
|
-
trade: Trade object representing the trade
|
|
1377
|
-
percentage: float representing the percentage
|
|
1378
|
-
that the stop loss should
|
|
1379
|
-
|
|
1380
|
-
or
|
|
1381
|
-
|
|
1382
|
-
|
|
1404
|
+
trade (Trade): Trade object representing the trade
|
|
1405
|
+
percentage (float): float representing the percentage
|
|
1406
|
+
of the open price that the stop loss should
|
|
1407
|
+
be set at. This must be a positive
|
|
1408
|
+
number, e.g. 5 for 5%, or 10 for 10%.
|
|
1409
|
+
trailing (bool): Whether the stop loss should be trailing
|
|
1410
|
+
or fixed.
|
|
1411
|
+
sell_percentage (float): float representing the
|
|
1412
|
+
percentage of the trade that should be sold if the
|
|
1413
|
+
stop loss is triggered
|
|
1414
|
+
created_at: datetime: The date and time when the stop loss
|
|
1415
|
+
was created. If not specified, the current date and time
|
|
1416
|
+
will be used.
|
|
1383
1417
|
|
|
1384
1418
|
Returns:
|
|
1385
1419
|
None
|
|
1386
1420
|
"""
|
|
1387
|
-
self.trade_service.add_stop_loss(
|
|
1421
|
+
return self.trade_service.add_stop_loss(
|
|
1388
1422
|
trade,
|
|
1389
1423
|
percentage=percentage,
|
|
1390
|
-
|
|
1424
|
+
trailing=trailing,
|
|
1391
1425
|
sell_percentage=sell_percentage,
|
|
1426
|
+
created_at=created_at,
|
|
1392
1427
|
)
|
|
1393
|
-
return self.trade_service.get(trade.id)
|
|
1394
1428
|
|
|
1395
1429
|
def add_take_profit(
|
|
1396
1430
|
self,
|
|
1397
|
-
trade,
|
|
1431
|
+
trade: Trade,
|
|
1398
1432
|
percentage: float,
|
|
1399
|
-
|
|
1433
|
+
trailing: bool = False,
|
|
1400
1434
|
sell_percentage: float = 100,
|
|
1401
|
-
|
|
1435
|
+
created_at: datetime = None,
|
|
1436
|
+
) -> TradeTakeProfit:
|
|
1402
1437
|
"""
|
|
1403
1438
|
Function to add a take profit to a trade. This function will add a
|
|
1404
1439
|
take profit to the specified trade. If the take profit is triggered,
|
|
@@ -1418,24 +1453,30 @@ class Context:
|
|
|
1418
1453
|
* BTC drops to $42,750 → Trade closes, securing profit.
|
|
1419
1454
|
|
|
1420
1455
|
Args:
|
|
1421
|
-
trade: Trade object representing the trade
|
|
1422
|
-
percentage: float representing the percentage
|
|
1423
|
-
that the stop loss should
|
|
1424
|
-
|
|
1425
|
-
or
|
|
1426
|
-
|
|
1427
|
-
|
|
1456
|
+
trade (Trade): Trade object representing the trade
|
|
1457
|
+
percentage (float): float representing the percentage
|
|
1458
|
+
of the open price that the stop loss should
|
|
1459
|
+
be set at. This must be a positive
|
|
1460
|
+
number, e.g. 5 for 5%, or 10 for 10%.
|
|
1461
|
+
trailing (bool): Whether the take profit should be trailing
|
|
1462
|
+
or fixed.
|
|
1463
|
+
sell_percentage (float): float representing the
|
|
1464
|
+
percentage of the trade that should be sold if the
|
|
1465
|
+
stop loss is triggered
|
|
1466
|
+
created_at: datetime: The date and time when the take profit
|
|
1467
|
+
was created. If not specified, the current date and time
|
|
1468
|
+
will be used.
|
|
1428
1469
|
|
|
1429
1470
|
Returns:
|
|
1430
1471
|
None
|
|
1431
1472
|
"""
|
|
1432
|
-
self.trade_service.add_take_profit(
|
|
1473
|
+
return self.trade_service.add_take_profit(
|
|
1433
1474
|
trade,
|
|
1434
1475
|
percentage=percentage,
|
|
1435
|
-
|
|
1476
|
+
trailing=trailing,
|
|
1436
1477
|
sell_percentage=sell_percentage,
|
|
1478
|
+
created_at=created_at,
|
|
1437
1479
|
)
|
|
1438
|
-
return self.trade_service.get(trade.id)
|
|
1439
1480
|
|
|
1440
1481
|
def close_trade(self, trade, precision=None) -> None:
|
|
1441
1482
|
"""
|
|
@@ -1451,7 +1492,6 @@ class Context:
|
|
|
1451
1492
|
Returns:
|
|
1452
1493
|
None
|
|
1453
1494
|
"""
|
|
1454
|
-
|
|
1455
1495
|
trade = self.trade_service.get(trade.id)
|
|
1456
1496
|
|
|
1457
1497
|
if TradeStatus.CLOSED.equals(trade.status):
|
|
@@ -1479,8 +1519,10 @@ class Context:
|
|
|
1479
1519
|
)
|
|
1480
1520
|
amount = position.get_amount()
|
|
1481
1521
|
|
|
1482
|
-
ticker = self.
|
|
1483
|
-
symbol=trade.symbol,
|
|
1522
|
+
ticker = self.data_provider_service.get_ticker_data(
|
|
1523
|
+
symbol=trade.symbol,
|
|
1524
|
+
market=portfolio.market,
|
|
1525
|
+
date=self.config[INDEX_DATETIME]
|
|
1484
1526
|
)
|
|
1485
1527
|
logger.info(f"Closing trade {trade.id} {trade.symbol}")
|
|
1486
1528
|
self.order_service.create(
|
|
@@ -1615,3 +1657,69 @@ class Context:
|
|
|
1615
1657
|
List[MarketCredential]: A list of all market credentials
|
|
1616
1658
|
"""
|
|
1617
1659
|
return self.market_credential_service.get_all()
|
|
1660
|
+
|
|
1661
|
+
def get_trading_symbol(self, portfolio_id=None):
|
|
1662
|
+
"""
|
|
1663
|
+
Function to get the trading symbol of a portfolio. If the
|
|
1664
|
+
portfolio_id parameter is specified, the function will return
|
|
1665
|
+
the trading symbol of the portfolio with the specified id.
|
|
1666
|
+
|
|
1667
|
+
Args:
|
|
1668
|
+
portfolio_id: The id of the portfolio to get the trading symbol for
|
|
1669
|
+
|
|
1670
|
+
Returns:
|
|
1671
|
+
str: The trading symbol of the portfolio
|
|
1672
|
+
"""
|
|
1673
|
+
if portfolio_id is None:
|
|
1674
|
+
if self.portfolio_service.count() > 1:
|
|
1675
|
+
raise OperationalException(
|
|
1676
|
+
"Multiple portfolios found. Please specify a "
|
|
1677
|
+
"portfolio identifier."
|
|
1678
|
+
)
|
|
1679
|
+
portfolio = self.portfolio_service.get_all()[0]
|
|
1680
|
+
else:
|
|
1681
|
+
portfolio = self.portfolio_service.get(portfolio_id)
|
|
1682
|
+
|
|
1683
|
+
return portfolio.trading_symbol
|
|
1684
|
+
|
|
1685
|
+
def get_take_profits(
|
|
1686
|
+
self, triggered: bool = None
|
|
1687
|
+
) -> List[TradeTakeProfit]:
|
|
1688
|
+
"""
|
|
1689
|
+
Function to get all take profits. If the triggered parameter
|
|
1690
|
+
is specified, the function will return all take profits that
|
|
1691
|
+
match the triggered status.
|
|
1692
|
+
|
|
1693
|
+
Args:
|
|
1694
|
+
triggered (bool): The triggered status of the take profits
|
|
1695
|
+
|
|
1696
|
+
Returns:
|
|
1697
|
+
List[TradeTakeProfit]: A list of take profits
|
|
1698
|
+
"""
|
|
1699
|
+
query_params = {}
|
|
1700
|
+
|
|
1701
|
+
if triggered is not None:
|
|
1702
|
+
query_params["triggered"] = triggered
|
|
1703
|
+
|
|
1704
|
+
return self.trade_take_profit_service.get_all(query_params)
|
|
1705
|
+
|
|
1706
|
+
def get_stop_losses(
|
|
1707
|
+
self, triggered: bool = None
|
|
1708
|
+
) -> List[TradeStopLoss]:
|
|
1709
|
+
"""
|
|
1710
|
+
Function to get all stop losses. If the triggered parameter
|
|
1711
|
+
is specified, the function will return all stop losses that
|
|
1712
|
+
match the triggered status.
|
|
1713
|
+
|
|
1714
|
+
Args:
|
|
1715
|
+
triggered (bool): The triggered status of the stop losses
|
|
1716
|
+
|
|
1717
|
+
Returns:
|
|
1718
|
+
List[TradeStopLoss]: A list of stop losses
|
|
1719
|
+
"""
|
|
1720
|
+
query_params = {}
|
|
1721
|
+
|
|
1722
|
+
if triggered is not None:
|
|
1723
|
+
query_params["triggered"] = triggered
|
|
1724
|
+
|
|
1725
|
+
return self.trade_stop_loss_service.get_all(query_params)
|