investing-algorithm-framework 7.19.14__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 +197 -0
- investing_algorithm_framework/app/__init__.py +47 -0
- investing_algorithm_framework/app/algorithm/__init__.py +7 -0
- investing_algorithm_framework/app/algorithm/algorithm.py +239 -0
- investing_algorithm_framework/app/algorithm/algorithm_factory.py +114 -0
- 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 +2204 -0
- investing_algorithm_framework/app/app_hook.py +28 -0
- investing_algorithm_framework/app/context.py +1667 -0
- investing_algorithm_framework/app/eventloop.py +590 -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/stop_loss_table.py +0 -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/__init__.py +35 -0
- investing_algorithm_framework/app/stateless/action_handlers/__init__.py +84 -0
- investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +8 -0
- investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +15 -0
- investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +40 -0
- investing_algorithm_framework/app/stateless/exception_handler.py +40 -0
- investing_algorithm_framework/app/strategy.py +675 -0
- investing_algorithm_framework/app/task.py +41 -0
- investing_algorithm_framework/app/web/__init__.py +5 -0
- investing_algorithm_framework/app/web/controllers/__init__.py +13 -0
- investing_algorithm_framework/app/web/controllers/orders.py +20 -0
- investing_algorithm_framework/app/web/controllers/portfolio.py +20 -0
- investing_algorithm_framework/app/web/controllers/positions.py +18 -0
- investing_algorithm_framework/app/web/create_app.py +20 -0
- investing_algorithm_framework/app/web/error_handler.py +59 -0
- investing_algorithm_framework/app/web/responses.py +20 -0
- investing_algorithm_framework/app/web/run_strategies.py +4 -0
- investing_algorithm_framework/app/web/schemas/__init__.py +12 -0
- investing_algorithm_framework/app/web/schemas/order.py +12 -0
- investing_algorithm_framework/app/web/schemas/portfolio.py +22 -0
- investing_algorithm_framework/app/web/schemas/position.py +15 -0
- investing_algorithm_framework/app/web/setup_cors.py +6 -0
- investing_algorithm_framework/cli/__init__.py +0 -0
- investing_algorithm_framework/cli/cli.py +207 -0
- investing_algorithm_framework/cli/deploy_to_aws_lambda.py +499 -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/create_app.py +54 -0
- investing_algorithm_framework/dependency_container.py +155 -0
- investing_algorithm_framework/domain/__init__.py +148 -0
- 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 +435 -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 +111 -0
- investing_algorithm_framework/domain/constants.py +83 -0
- investing_algorithm_framework/domain/data_provider.py +334 -0
- investing_algorithm_framework/domain/data_structures.py +42 -0
- investing_algorithm_framework/domain/decimal_parsing.py +40 -0
- investing_algorithm_framework/domain/exceptions.py +112 -0
- investing_algorithm_framework/domain/models/__init__.py +43 -0
- investing_algorithm_framework/domain/models/app_mode.py +34 -0
- investing_algorithm_framework/domain/models/base_model.py +25 -0
- 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/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 +6 -0
- investing_algorithm_framework/domain/models/order/order.py +384 -0
- investing_algorithm_framework/domain/models/order/order_side.py +36 -0
- investing_algorithm_framework/domain/models/order/order_status.py +37 -0
- investing_algorithm_framework/domain/models/order/order_type.py +30 -0
- investing_algorithm_framework/domain/models/portfolio/__init__.py +9 -0
- investing_algorithm_framework/domain/models/portfolio/portfolio.py +169 -0
- investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +93 -0
- investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +208 -0
- investing_algorithm_framework/domain/models/position/__init__.py +4 -0
- investing_algorithm_framework/domain/models/position/position.py +68 -0
- investing_algorithm_framework/domain/models/position/position_snapshot.py +47 -0
- investing_algorithm_framework/domain/models/snapshot_interval.py +45 -0
- investing_algorithm_framework/domain/models/strategy_profile.py +33 -0
- investing_algorithm_framework/domain/models/time_frame.py +153 -0
- investing_algorithm_framework/domain/models/time_interval.py +124 -0
- investing_algorithm_framework/domain/models/time_unit.py +149 -0
- 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 +13 -0
- investing_algorithm_framework/domain/models/trade/trade.py +388 -0
- investing_algorithm_framework/domain/models/trade/trade_risk_type.py +34 -0
- investing_algorithm_framework/domain/models/trade/trade_status.py +40 -0
- investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +267 -0
- investing_algorithm_framework/domain/models/trade/trade_take_profit.py +303 -0
- investing_algorithm_framework/domain/order_executor.py +112 -0
- investing_algorithm_framework/domain/portfolio_provider.py +118 -0
- investing_algorithm_framework/domain/positions/__init__.py +4 -0
- investing_algorithm_framework/domain/positions/position_size.py +41 -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/stateless_actions.py +7 -0
- investing_algorithm_framework/domain/strategy.py +44 -0
- investing_algorithm_framework/domain/utils/__init__.py +27 -0
- investing_algorithm_framework/domain/utils/csv.py +104 -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 +41 -0
- investing_algorithm_framework/domain/utils/signatures.py +17 -0
- investing_algorithm_framework/domain/utils/stoppable_thread.py +26 -0
- investing_algorithm_framework/domain/utils/synchronized.py +12 -0
- investing_algorithm_framework/download_data.py +108 -0
- investing_algorithm_framework/infrastructure/__init__.py +50 -0
- investing_algorithm_framework/infrastructure/data_providers/__init__.py +36 -0
- investing_algorithm_framework/infrastructure/data_providers/ccxt.py +1143 -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 +10 -0
- investing_algorithm_framework/infrastructure/database/sql_alchemy.py +120 -0
- investing_algorithm_framework/infrastructure/models/__init__.py +16 -0
- investing_algorithm_framework/infrastructure/models/decimal_parser.py +14 -0
- investing_algorithm_framework/infrastructure/models/model_extension.py +6 -0
- investing_algorithm_framework/infrastructure/models/order/__init__.py +4 -0
- investing_algorithm_framework/infrastructure/models/order/order.py +124 -0
- 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 +4 -0
- investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +37 -0
- investing_algorithm_framework/infrastructure/models/portfolio/sql_portfolio.py +114 -0
- investing_algorithm_framework/infrastructure/models/position/__init__.py +4 -0
- investing_algorithm_framework/infrastructure/models/position/position.py +63 -0
- investing_algorithm_framework/infrastructure/models/position/position_snapshot.py +23 -0
- 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 +40 -0
- investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +41 -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 +21 -0
- investing_algorithm_framework/infrastructure/repositories/order_metadata_repository.py +17 -0
- investing_algorithm_framework/infrastructure/repositories/order_repository.py +96 -0
- investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +30 -0
- investing_algorithm_framework/infrastructure/repositories/portfolio_snapshot_repository.py +56 -0
- investing_algorithm_framework/infrastructure/repositories/position_repository.py +66 -0
- investing_algorithm_framework/infrastructure/repositories/position_snapshot_repository.py +21 -0
- investing_algorithm_framework/infrastructure/repositories/repository.py +299 -0
- investing_algorithm_framework/infrastructure/repositories/trade_repository.py +71 -0
- investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +23 -0
- investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +23 -0
- investing_algorithm_framework/infrastructure/services/__init__.py +7 -0
- investing_algorithm_framework/infrastructure/services/aws/__init__.py +6 -0
- investing_algorithm_framework/infrastructure/services/aws/state_handler.py +113 -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/services/__init__.py +132 -0
- investing_algorithm_framework/services/backtesting/__init__.py +5 -0
- investing_algorithm_framework/services/backtesting/backtest_service.py +651 -0
- investing_algorithm_framework/services/configuration_service.py +96 -0
- 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/services/market_credential_service.py +40 -0
- investing_algorithm_framework/services/metrics/__init__.py +114 -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 +181 -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 +83 -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 +157 -0
- investing_algorithm_framework/services/metrics/trades.py +500 -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 +97 -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/portfolios/portfolio_configuration_service.py +75 -0
- 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/positions/position_snapshot_service.py +18 -0
- investing_algorithm_framework/services/repository_service.py +40 -0
- investing_algorithm_framework/services/trade_order_evaluator/__init__.py +9 -0
- investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +132 -0
- investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +66 -0
- investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +41 -0
- investing_algorithm_framework/services/trade_service/__init__.py +3 -0
- investing_algorithm_framework/services/trade_service/trade_service.py +1083 -0
- investing_algorithm_framework-7.19.14.dist-info/LICENSE +201 -0
- investing_algorithm_framework-7.19.14.dist-info/METADATA +459 -0
- investing_algorithm_framework-7.19.14.dist-info/RECORD +260 -0
- investing_algorithm_framework-7.19.14.dist-info/WHEEL +4 -0
- investing_algorithm_framework-7.19.14.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,675 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import List, Dict, Any
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
from investing_algorithm_framework.domain import OperationalException, Position
|
|
7
|
+
from investing_algorithm_framework.domain import PositionSize, \
|
|
8
|
+
TimeUnit, StrategyProfile, Trade, DataSource, OrderSide
|
|
9
|
+
from .context import Context
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TradingStrategy:
|
|
13
|
+
"""
|
|
14
|
+
TradingStrategy is the base class for all trading strategies. A trading
|
|
15
|
+
strategy is a set of rules that defines when to buy or sell an asset.
|
|
16
|
+
|
|
17
|
+
Attributes:
|
|
18
|
+
time_unit: TimeUnit - the time unit of the strategy that defines
|
|
19
|
+
when the strategy should run e.g. HOUR, DAY, WEEK, MONTH
|
|
20
|
+
interval: int - the interval of the strategy that defines how often
|
|
21
|
+
the strategy should run within the time unit e.g. every 5 hours,
|
|
22
|
+
every 2 days, every 3 weeks, every 4 months
|
|
23
|
+
worker_id (optional): str - the id of the worker
|
|
24
|
+
strategy_id (optional): str - the id of the strategy
|
|
25
|
+
decorated (optional): function - the decorated function
|
|
26
|
+
data_sources (List[DataSource] optional): the list of data
|
|
27
|
+
sources to use for the strategy. The data sources will be used
|
|
28
|
+
to indentify data providers that will be called to gather data
|
|
29
|
+
and pass to the strategy before its run.
|
|
30
|
+
metadata (optional): Dict[str, Any] - a dictionary
|
|
31
|
+
containing metadata about the strategy. This can be used to
|
|
32
|
+
store additional information about the strategy, such as its
|
|
33
|
+
author, version, description, params etc.
|
|
34
|
+
"""
|
|
35
|
+
time_unit: TimeUnit = None
|
|
36
|
+
interval: int = None
|
|
37
|
+
worker_id: str = None
|
|
38
|
+
strategy_id: str = None
|
|
39
|
+
decorated = None
|
|
40
|
+
data_sources: List[DataSource] = []
|
|
41
|
+
traces = None
|
|
42
|
+
context: Context = None
|
|
43
|
+
metadata: Dict[str, Any] = None
|
|
44
|
+
position_sizes: List[PositionSize] = []
|
|
45
|
+
symbols: List[str] = []
|
|
46
|
+
trading_symbol: str = None
|
|
47
|
+
|
|
48
|
+
def __init__(
|
|
49
|
+
self,
|
|
50
|
+
strategy_id=None,
|
|
51
|
+
time_unit=None,
|
|
52
|
+
interval=None,
|
|
53
|
+
data_sources=None,
|
|
54
|
+
metadata=None,
|
|
55
|
+
position_sizes=None,
|
|
56
|
+
symbols=None,
|
|
57
|
+
trading_symbol=None,
|
|
58
|
+
worker_id=None,
|
|
59
|
+
decorated=None
|
|
60
|
+
):
|
|
61
|
+
if time_unit is not None:
|
|
62
|
+
self.time_unit = TimeUnit.from_value(time_unit)
|
|
63
|
+
else:
|
|
64
|
+
# Check if time_unit is None
|
|
65
|
+
if self.time_unit is None:
|
|
66
|
+
raise OperationalException(
|
|
67
|
+
f"Time unit attribute not set for "
|
|
68
|
+
f"strategy instance {self.strategy_id}"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
self.time_unit = TimeUnit.from_value(self.time_unit)
|
|
72
|
+
|
|
73
|
+
if interval is not None:
|
|
74
|
+
self.interval = interval
|
|
75
|
+
|
|
76
|
+
if data_sources is not None:
|
|
77
|
+
self.data_sources = data_sources
|
|
78
|
+
|
|
79
|
+
self.metadata = metadata
|
|
80
|
+
|
|
81
|
+
if decorated is not None:
|
|
82
|
+
self.decorated = decorated
|
|
83
|
+
|
|
84
|
+
if worker_id is not None:
|
|
85
|
+
self.worker_id = worker_id
|
|
86
|
+
elif self.decorated:
|
|
87
|
+
self.worker_id = decorated.__name__
|
|
88
|
+
else:
|
|
89
|
+
self.worker_id = self.__class__.__name__
|
|
90
|
+
|
|
91
|
+
if strategy_id is not None:
|
|
92
|
+
self.strategy_id = strategy_id
|
|
93
|
+
else:
|
|
94
|
+
self.strategy_id = self.worker_id
|
|
95
|
+
|
|
96
|
+
if position_sizes is not None:
|
|
97
|
+
self.position_sizes = position_sizes
|
|
98
|
+
|
|
99
|
+
if symbols is not None:
|
|
100
|
+
self.symbols = symbols
|
|
101
|
+
|
|
102
|
+
if trading_symbol is not None:
|
|
103
|
+
self.trading_symbol = trading_symbol
|
|
104
|
+
|
|
105
|
+
# Check if interval is None
|
|
106
|
+
if self.interval is None:
|
|
107
|
+
raise OperationalException(
|
|
108
|
+
f"Interval not set for strategy instance {self.strategy_id}"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# context initialization
|
|
112
|
+
self._context = None
|
|
113
|
+
self._last_run = None
|
|
114
|
+
|
|
115
|
+
def generate_buy_signals(
|
|
116
|
+
self, data: Dict[str, Any]
|
|
117
|
+
) -> Dict[str, pd.Series]:
|
|
118
|
+
"""
|
|
119
|
+
Function that needs to be implemented by the user.
|
|
120
|
+
This function should return a pandas Series containing the buy signals.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
data (Dict[str, Any]): All the data that matched the
|
|
124
|
+
data sources of the strategy.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
Dict[str, Series]: A dictionary where the keys are the
|
|
128
|
+
symbols and the values are pandas Series containing
|
|
129
|
+
the buy signals.
|
|
130
|
+
"""
|
|
131
|
+
raise NotImplementedError(
|
|
132
|
+
"generate_buy_signals method not implemented"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
def generate_sell_signals(
|
|
136
|
+
self, data: Dict[str, Any]
|
|
137
|
+
) -> Dict[str, pd.Series]:
|
|
138
|
+
"""
|
|
139
|
+
Function that needs to be implemented by the user.
|
|
140
|
+
This function should return a pandas Series containing
|
|
141
|
+
the sell signals.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
data (Dict[str, Any]): All the data that matched the
|
|
145
|
+
data sources of the strategy.
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
Dict[str, Series]: A dictionary where the keys are the
|
|
149
|
+
symbols and the values are pandas Series containing
|
|
150
|
+
the sell signals.
|
|
151
|
+
"""
|
|
152
|
+
raise NotImplementedError(
|
|
153
|
+
"generate_sell_signals method not implemented"
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
def run_strategy(self, context: Context, data: Dict[str, Any]):
|
|
157
|
+
"""
|
|
158
|
+
Main function for running your strategy. This function will be called
|
|
159
|
+
by the framework when the trigger of your strategy is met.
|
|
160
|
+
|
|
161
|
+
During execution of this function, the context and market data
|
|
162
|
+
will be passed to the function. The context is an instance of
|
|
163
|
+
the Context class, this class has various methods to do operations
|
|
164
|
+
with your portfolio, orders, trades, positions and other components.
|
|
165
|
+
|
|
166
|
+
The market data is a dictionary containing all the data retrieved
|
|
167
|
+
from the specified data sources.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
context (Context): The context of the strategy. This is an instance
|
|
171
|
+
of the Context class, this class has various methods to do
|
|
172
|
+
operations with your portfolio, orders, trades, positions and
|
|
173
|
+
other components.
|
|
174
|
+
data (Dict[str, Any]): The data for the strategy.
|
|
175
|
+
This is a dictionary containing all the data retrieved from the
|
|
176
|
+
specified data sources.
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
None
|
|
180
|
+
"""
|
|
181
|
+
self.context = context
|
|
182
|
+
buy_signals = self.generate_buy_signals(data)
|
|
183
|
+
sell_signals = self.generate_sell_signals(data)
|
|
184
|
+
|
|
185
|
+
for symbol in self.symbols:
|
|
186
|
+
|
|
187
|
+
if self.has_open_orders(symbol):
|
|
188
|
+
continue
|
|
189
|
+
|
|
190
|
+
if not self.has_position(symbol) \
|
|
191
|
+
and not self.has_open_orders(symbol):
|
|
192
|
+
|
|
193
|
+
if symbol in buy_signals:
|
|
194
|
+
signals = buy_signals[symbol]
|
|
195
|
+
|
|
196
|
+
# Check in the last row if there is a buy signal
|
|
197
|
+
last_row = signals.iloc[-1]
|
|
198
|
+
if last_row:
|
|
199
|
+
position_size = next(
|
|
200
|
+
(ps for ps in self.position_sizes
|
|
201
|
+
if ps.symbol == symbol), None
|
|
202
|
+
)
|
|
203
|
+
if position_size is None:
|
|
204
|
+
raise OperationalException(
|
|
205
|
+
f"No position size defined for symbol "
|
|
206
|
+
f"{symbol} in strategy "
|
|
207
|
+
f"{self.strategy_id}"
|
|
208
|
+
)
|
|
209
|
+
full_symbol = (f"{symbol}/"
|
|
210
|
+
f"{self.context.get_trading_symbol()}")
|
|
211
|
+
price = self.context.get_latest_price(full_symbol)
|
|
212
|
+
amount = position_size.get_size(
|
|
213
|
+
self.context.get_portfolio(), price
|
|
214
|
+
)
|
|
215
|
+
order_amount = amount / price
|
|
216
|
+
self.create_limit_order(
|
|
217
|
+
target_symbol=symbol,
|
|
218
|
+
order_side=OrderSide.BUY,
|
|
219
|
+
amount=order_amount,
|
|
220
|
+
price=price,
|
|
221
|
+
execute=True,
|
|
222
|
+
validate=True,
|
|
223
|
+
sync=True
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
if self.has_position(symbol) \
|
|
227
|
+
and not self.has_open_orders(symbol):
|
|
228
|
+
|
|
229
|
+
# Check in the last row if there is a sell signal
|
|
230
|
+
if symbol in sell_signals:
|
|
231
|
+
signals = sell_signals[symbol]
|
|
232
|
+
|
|
233
|
+
# Check in the last row if there is a sell signal
|
|
234
|
+
last_row = signals.iloc[-1]
|
|
235
|
+
|
|
236
|
+
if last_row:
|
|
237
|
+
position = self.get_position(symbol)
|
|
238
|
+
|
|
239
|
+
if position is None:
|
|
240
|
+
raise OperationalException(
|
|
241
|
+
f"No position found for symbol {symbol} "
|
|
242
|
+
f"in strategy {self.strategy_id}"
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
full_symbol = (f"{symbol}/"
|
|
246
|
+
f"{self.context.get_trading_symbol()}")
|
|
247
|
+
price = self.context.get_latest_price(full_symbol)
|
|
248
|
+
self.create_limit_order(
|
|
249
|
+
target_symbol=symbol,
|
|
250
|
+
order_side=OrderSide.SELL,
|
|
251
|
+
amount=position.amount,
|
|
252
|
+
execute=True,
|
|
253
|
+
validate=True,
|
|
254
|
+
sync=True,
|
|
255
|
+
price=price
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
def apply_strategy(self, context, data):
|
|
259
|
+
if self.decorated:
|
|
260
|
+
self.decorated(context=context, data=data)
|
|
261
|
+
else:
|
|
262
|
+
raise NotImplementedError("Apply strategy is not implemented")
|
|
263
|
+
|
|
264
|
+
@property
|
|
265
|
+
def strategy_profile(self):
|
|
266
|
+
return StrategyProfile(
|
|
267
|
+
strategy_id=self.worker_id,
|
|
268
|
+
interval=self.interval,
|
|
269
|
+
time_unit=self.time_unit,
|
|
270
|
+
data_sources=self.data_sources
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
def _update_trades_and_orders(self, market_data):
|
|
274
|
+
self.context.order_service.check_pending_orders()
|
|
275
|
+
self.context.trade_service\
|
|
276
|
+
.update_trades_with_market_data(market_data)
|
|
277
|
+
|
|
278
|
+
def _update_trades_and_orders_for_backtest(self, market_data):
|
|
279
|
+
self.context.order_service.check_pending_orders(market_data)
|
|
280
|
+
self.context.trade_service\
|
|
281
|
+
.update_trades_with_market_data(market_data)
|
|
282
|
+
|
|
283
|
+
def _check_stop_losses(self):
|
|
284
|
+
"""
|
|
285
|
+
Check if there are any stop losses that result in trades being closed.
|
|
286
|
+
"""
|
|
287
|
+
trade_service = self.context.trade_service
|
|
288
|
+
|
|
289
|
+
stop_losses_orders_data = trade_service\
|
|
290
|
+
.get_triggered_stop_loss_orders()
|
|
291
|
+
|
|
292
|
+
order_service = self.context.order_service
|
|
293
|
+
|
|
294
|
+
for stop_loss_order in stop_losses_orders_data:
|
|
295
|
+
order_service.create(stop_loss_order)
|
|
296
|
+
|
|
297
|
+
def _check_take_profits(self):
|
|
298
|
+
"""
|
|
299
|
+
Check if there are any take profits that result in trades being closed.
|
|
300
|
+
"""
|
|
301
|
+
trade_service = self.context.trade_service
|
|
302
|
+
take_profit_orders_data = trade_service.\
|
|
303
|
+
get_triggered_take_profit_orders()
|
|
304
|
+
order_service = self.context.order_service
|
|
305
|
+
|
|
306
|
+
for take_profit_order in take_profit_orders_data:
|
|
307
|
+
order_service.create(take_profit_order)
|
|
308
|
+
|
|
309
|
+
def on_trade_closed(self, context: Context, trade: Trade):
|
|
310
|
+
pass
|
|
311
|
+
|
|
312
|
+
def on_trade_updated(self, context: Context, trade: Trade):
|
|
313
|
+
pass
|
|
314
|
+
|
|
315
|
+
def on_trade_created(self, context: Context, trade: Trade):
|
|
316
|
+
pass
|
|
317
|
+
|
|
318
|
+
def on_trade_opened(self, context: Context, trade: Trade):
|
|
319
|
+
pass
|
|
320
|
+
|
|
321
|
+
def on_trade_stop_loss_triggered(self, context: Context, trade: Trade):
|
|
322
|
+
pass
|
|
323
|
+
|
|
324
|
+
def on_trade_trailing_stop_loss_triggered(
|
|
325
|
+
self, context: Context, trade: Trade
|
|
326
|
+
):
|
|
327
|
+
pass
|
|
328
|
+
|
|
329
|
+
def on_trade_take_profit_triggered(
|
|
330
|
+
self, context: Context, trade: Trade
|
|
331
|
+
):
|
|
332
|
+
pass
|
|
333
|
+
|
|
334
|
+
def on_trade_stop_loss_updated(self, context: Context, trade: Trade):
|
|
335
|
+
pass
|
|
336
|
+
|
|
337
|
+
def on_trade_trailing_stop_loss_updated(
|
|
338
|
+
self, context: Context, trade: Trade
|
|
339
|
+
):
|
|
340
|
+
pass
|
|
341
|
+
|
|
342
|
+
def on_trade_take_profit_updated(self, context: Context, trade: Trade):
|
|
343
|
+
pass
|
|
344
|
+
|
|
345
|
+
def on_trade_stop_loss_created(self, context: Context, trade: Trade):
|
|
346
|
+
pass
|
|
347
|
+
|
|
348
|
+
def on_trade_trailing_stop_loss_created(
|
|
349
|
+
self, context: Context, trade: Trade
|
|
350
|
+
):
|
|
351
|
+
pass
|
|
352
|
+
|
|
353
|
+
def on_trade_take_profit_created(self, context: Context, trade: Trade):
|
|
354
|
+
pass
|
|
355
|
+
|
|
356
|
+
@property
|
|
357
|
+
def strategy_identifier(self):
|
|
358
|
+
|
|
359
|
+
if self.strategy_id is not None:
|
|
360
|
+
return self.strategy_id
|
|
361
|
+
|
|
362
|
+
return self.worker_id
|
|
363
|
+
|
|
364
|
+
def has_open_orders(
|
|
365
|
+
self, target_symbol=None, identifier=None, market=None
|
|
366
|
+
) -> bool:
|
|
367
|
+
"""
|
|
368
|
+
Check if there are open orders for a given symbol
|
|
369
|
+
|
|
370
|
+
Args:
|
|
371
|
+
target_symbol (str): The symbol of the asset e.g BTC if the
|
|
372
|
+
asset is BTC/USDT
|
|
373
|
+
identifier (str): The identifier of the portfolio
|
|
374
|
+
market (str): The market of the asset
|
|
375
|
+
|
|
376
|
+
Returns:
|
|
377
|
+
bool: True if there are open orders, False otherwise
|
|
378
|
+
"""
|
|
379
|
+
return self.context.has_open_orders(
|
|
380
|
+
target_symbol=target_symbol, identifier=identifier, market=market
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
def create_limit_order(
|
|
384
|
+
self,
|
|
385
|
+
target_symbol,
|
|
386
|
+
price,
|
|
387
|
+
order_side,
|
|
388
|
+
amount=None,
|
|
389
|
+
amount_trading_symbol=None,
|
|
390
|
+
percentage=None,
|
|
391
|
+
percentage_of_portfolio=None,
|
|
392
|
+
percentage_of_position=None,
|
|
393
|
+
precision=None,
|
|
394
|
+
market=None,
|
|
395
|
+
execute=True,
|
|
396
|
+
validate=True,
|
|
397
|
+
sync=True
|
|
398
|
+
):
|
|
399
|
+
"""
|
|
400
|
+
Function to create a limit order. This function will create
|
|
401
|
+
a limit order and execute it if the execute parameter is set to True.
|
|
402
|
+
If the validate parameter is set to True, the order will be validated
|
|
403
|
+
|
|
404
|
+
Args:
|
|
405
|
+
target_symbol: The symbol of the asset to trade
|
|
406
|
+
price: The price of the asset
|
|
407
|
+
order_side: The side of the order
|
|
408
|
+
amount (optional): The amount of the asset to trade
|
|
409
|
+
amount_trading_symbol (optional): The amount of the trading
|
|
410
|
+
symbol to trade
|
|
411
|
+
percentage (optional): The percentage of the portfolio to
|
|
412
|
+
allocate to the order
|
|
413
|
+
percentage_of_portfolio (optional): The percentage of
|
|
414
|
+
the portfolio to allocate to the order
|
|
415
|
+
percentage_of_position (optional): The percentage of
|
|
416
|
+
the position to allocate to the order.
|
|
417
|
+
(Only supported for SELL orders)
|
|
418
|
+
precision (optional): The precision of the amount
|
|
419
|
+
market (optional): The market to trade the asset
|
|
420
|
+
execute (optional): Default True. If set to True, the order
|
|
421
|
+
will be executed
|
|
422
|
+
validate (optional): Default True. If set to True, the order
|
|
423
|
+
will be validated
|
|
424
|
+
sync (optional): Default True. If set to True, the created
|
|
425
|
+
order will be synced with the portfolio of the context
|
|
426
|
+
|
|
427
|
+
Returns:
|
|
428
|
+
Order: Instance of the order created
|
|
429
|
+
"""
|
|
430
|
+
self.context.create_limit_order(
|
|
431
|
+
target_symbol=target_symbol,
|
|
432
|
+
price=price,
|
|
433
|
+
order_side=order_side,
|
|
434
|
+
amount=amount,
|
|
435
|
+
amount_trading_symbol=amount_trading_symbol,
|
|
436
|
+
percentage=percentage,
|
|
437
|
+
percentage_of_portfolio=percentage_of_portfolio,
|
|
438
|
+
percentage_of_position=percentage_of_position,
|
|
439
|
+
precision=precision,
|
|
440
|
+
market=market,
|
|
441
|
+
execute=execute,
|
|
442
|
+
validate=validate,
|
|
443
|
+
sync=sync
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
def close_position(
|
|
447
|
+
self, symbol, market=None, identifier=None, precision=None
|
|
448
|
+
):
|
|
449
|
+
"""
|
|
450
|
+
Function to close a position. This function will close a position
|
|
451
|
+
by creating a market order to sell the position. If the precision
|
|
452
|
+
parameter is specified, the amount of the order will be rounded
|
|
453
|
+
down to the specified precision.
|
|
454
|
+
|
|
455
|
+
Args:
|
|
456
|
+
symbol: The symbol of the asset
|
|
457
|
+
market: The market of the asset
|
|
458
|
+
identifier: The identifier of the portfolio
|
|
459
|
+
precision: The precision of the amount
|
|
460
|
+
|
|
461
|
+
Returns:
|
|
462
|
+
None
|
|
463
|
+
"""
|
|
464
|
+
self.context.close_position(
|
|
465
|
+
symbol=symbol,
|
|
466
|
+
market=market,
|
|
467
|
+
identifier=identifier,
|
|
468
|
+
precision=precision
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
def get_positions(
|
|
472
|
+
self,
|
|
473
|
+
market=None,
|
|
474
|
+
identifier=None,
|
|
475
|
+
amount_gt=None,
|
|
476
|
+
amount_gte=None,
|
|
477
|
+
amount_lt=None,
|
|
478
|
+
amount_lte=None
|
|
479
|
+
) -> List[Position]:
|
|
480
|
+
"""
|
|
481
|
+
Function to get all positions. This function will return all
|
|
482
|
+
positions that match the specified query parameters. If the
|
|
483
|
+
market parameter is specified, the positions of the specified
|
|
484
|
+
market will be returned. If the identifier parameter is
|
|
485
|
+
specified, the positions of the specified portfolio will be
|
|
486
|
+
returned. If the amount_gt parameter is specified, the positions
|
|
487
|
+
with an amount greater than the specified amount will be returned.
|
|
488
|
+
If the amount_gte parameter is specified, the positions with an
|
|
489
|
+
amount greater than or equal to the specified amount will be
|
|
490
|
+
returned. If the amount_lt parameter is specified, the positions
|
|
491
|
+
with an amount less than the specified amount will be returned.
|
|
492
|
+
If the amount_lte parameter is specified, the positions with an
|
|
493
|
+
amount less than or equal to the specified amount will be returned.
|
|
494
|
+
|
|
495
|
+
Args:
|
|
496
|
+
market: The market of the portfolio where the positions are
|
|
497
|
+
identifier: The identifier of the portfolio
|
|
498
|
+
amount_gt: The amount of the asset must be greater than this
|
|
499
|
+
amount_gte: The amount of the asset must be greater than or
|
|
500
|
+
equal to this
|
|
501
|
+
amount_lt: The amount of the asset must be less than this
|
|
502
|
+
amount_lte: The amount of the asset must be less than or equal
|
|
503
|
+
to this
|
|
504
|
+
|
|
505
|
+
Returns:
|
|
506
|
+
List[Position]: A list of positions that match the query parameters
|
|
507
|
+
"""
|
|
508
|
+
return self.context.get_positions(
|
|
509
|
+
market=market,
|
|
510
|
+
identifier=identifier,
|
|
511
|
+
amount_gt=amount_gt,
|
|
512
|
+
amount_gte=amount_gte,
|
|
513
|
+
amount_lt=amount_lt,
|
|
514
|
+
amount_lte=amount_lte
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
def get_trades(self, market=None) -> List[Trade]:
|
|
518
|
+
"""
|
|
519
|
+
Function to get all trades. This function will return all trades
|
|
520
|
+
that match the specified query parameters. If the market parameter
|
|
521
|
+
is specified, the trades with the specified market will be returned.
|
|
522
|
+
|
|
523
|
+
Args:
|
|
524
|
+
market: The market of the asset
|
|
525
|
+
|
|
526
|
+
Returns:
|
|
527
|
+
List[Trade]: A list of trades that match the query parameters
|
|
528
|
+
"""
|
|
529
|
+
return self.context.get_trades(market)
|
|
530
|
+
|
|
531
|
+
def get_closed_trades(self) -> List[Trade]:
|
|
532
|
+
"""
|
|
533
|
+
Function to get all closed trades. This function will return all
|
|
534
|
+
closed trades of the context.
|
|
535
|
+
|
|
536
|
+
Returns:
|
|
537
|
+
List[Trade]: A list of closed trades
|
|
538
|
+
"""
|
|
539
|
+
return self.context.get_closed_trades()
|
|
540
|
+
|
|
541
|
+
def get_open_trades(self, target_symbol=None, market=None) -> List[Trade]:
|
|
542
|
+
"""
|
|
543
|
+
Function to get all open trades. This function will return all
|
|
544
|
+
open trades that match the specified query parameters. If the
|
|
545
|
+
target_symbol parameter is specified, the open trades with the
|
|
546
|
+
specified target symbol will be returned. If the market parameter
|
|
547
|
+
is specified, the open trades with the specified market will be
|
|
548
|
+
returned.
|
|
549
|
+
|
|
550
|
+
Args:
|
|
551
|
+
target_symbol: The symbol of the asset
|
|
552
|
+
market: The market of the asset
|
|
553
|
+
|
|
554
|
+
Returns:
|
|
555
|
+
List[Trade]: A list of open trades that match the query parameters
|
|
556
|
+
"""
|
|
557
|
+
return self.context.get_open_trades(target_symbol, market)
|
|
558
|
+
|
|
559
|
+
def close_trade(self, trade, market=None, precision=None) -> None:
|
|
560
|
+
"""
|
|
561
|
+
Function to close a trade. This function will close a trade by
|
|
562
|
+
creating a market order to sell the position. If the precision
|
|
563
|
+
parameter is specified, the amount of the order will be rounded
|
|
564
|
+
down to the specified precision.
|
|
565
|
+
|
|
566
|
+
Args:
|
|
567
|
+
trade: Trade - The trade to close
|
|
568
|
+
market: str - The market of the trade
|
|
569
|
+
precision: float - The precision of the amount
|
|
570
|
+
|
|
571
|
+
Returns:
|
|
572
|
+
None
|
|
573
|
+
"""
|
|
574
|
+
self.context.close_trade(
|
|
575
|
+
trade=trade, market=market, precision=precision
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
def get_number_of_positions(self):
|
|
579
|
+
"""
|
|
580
|
+
Returns the number of positions that have a positive amount.
|
|
581
|
+
|
|
582
|
+
Returns:
|
|
583
|
+
int: The number of positions
|
|
584
|
+
"""
|
|
585
|
+
return self.context.get_number_of_positions()
|
|
586
|
+
|
|
587
|
+
def get_position(
|
|
588
|
+
self, symbol, market=None, identifier=None
|
|
589
|
+
) -> Position:
|
|
590
|
+
"""
|
|
591
|
+
Function to get a position. This function will return the
|
|
592
|
+
position that matches the specified query parameters. If the
|
|
593
|
+
market parameter is specified, the position of the specified
|
|
594
|
+
market will be returned. If the identifier parameter is
|
|
595
|
+
specified, the position of the specified portfolio will be
|
|
596
|
+
returned.
|
|
597
|
+
|
|
598
|
+
Args:
|
|
599
|
+
symbol: The symbol of the asset that represents the position
|
|
600
|
+
market: The market of the portfolio where the position is located
|
|
601
|
+
identifier: The identifier of the portfolio
|
|
602
|
+
|
|
603
|
+
Returns:
|
|
604
|
+
Position: The position that matches the query parameters
|
|
605
|
+
"""
|
|
606
|
+
return self.context.get_position(
|
|
607
|
+
symbol=symbol,
|
|
608
|
+
market=market,
|
|
609
|
+
identifier=identifier
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
def has_position(
|
|
613
|
+
self,
|
|
614
|
+
symbol,
|
|
615
|
+
market=None,
|
|
616
|
+
identifier=None,
|
|
617
|
+
amount_gt=0,
|
|
618
|
+
amount_gte=None,
|
|
619
|
+
amount_lt=None,
|
|
620
|
+
amount_lte=None
|
|
621
|
+
):
|
|
622
|
+
"""
|
|
623
|
+
Function to check if a position exists. This function will return
|
|
624
|
+
True if a position exists, False otherwise. This function will check
|
|
625
|
+
if the amount > 0 condition by default.
|
|
626
|
+
|
|
627
|
+
Args:
|
|
628
|
+
param symbol: The symbol of the asset
|
|
629
|
+
param market: The market of the asset
|
|
630
|
+
param identifier: The identifier of the portfolio
|
|
631
|
+
param amount_gt: The amount of the asset must be greater than this
|
|
632
|
+
param amount_gte: The amount of the asset must be greater than
|
|
633
|
+
or equal to this
|
|
634
|
+
param amount_lt: The amount of the asset must be less than this
|
|
635
|
+
param amount_lte: The amount of the asset must be less than
|
|
636
|
+
or equal to this
|
|
637
|
+
|
|
638
|
+
Returns:
|
|
639
|
+
Boolean: True if a position exists, False otherwise
|
|
640
|
+
"""
|
|
641
|
+
return self.context.has_position(
|
|
642
|
+
symbol=symbol,
|
|
643
|
+
market=market,
|
|
644
|
+
identifier=identifier,
|
|
645
|
+
amount_gt=amount_gt,
|
|
646
|
+
amount_gte=amount_gte,
|
|
647
|
+
amount_lt=amount_lt,
|
|
648
|
+
amount_lte=amount_lte
|
|
649
|
+
)
|
|
650
|
+
|
|
651
|
+
def has_balance(self, symbol, amount, market=None):
|
|
652
|
+
"""
|
|
653
|
+
Function to check if the portfolio has enough balance to
|
|
654
|
+
create an order. This function will return True if the
|
|
655
|
+
portfolio has enough balance to create an order, False
|
|
656
|
+
otherwise.
|
|
657
|
+
|
|
658
|
+
Args:
|
|
659
|
+
symbol: The symbol of the asset
|
|
660
|
+
amount: The amount of the asset
|
|
661
|
+
market: The market of the asset
|
|
662
|
+
|
|
663
|
+
Returns:
|
|
664
|
+
Boolean: True if the portfolio has enough balance
|
|
665
|
+
"""
|
|
666
|
+
return self.context.has_balance(symbol, amount, market)
|
|
667
|
+
|
|
668
|
+
def last_run(self) -> datetime:
|
|
669
|
+
"""
|
|
670
|
+
Function to get the last run of the strategy
|
|
671
|
+
|
|
672
|
+
Returns:
|
|
673
|
+
DateTime: The last run of the strategy
|
|
674
|
+
"""
|
|
675
|
+
return self.context.last_run()
|