investing-algorithm-framework 1.3.1__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 +195 -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 +31 -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 +2233 -264
- 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/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/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/stateless/exception_handler.py +1 -1
- investing_algorithm_framework/app/strategy.py +873 -52
- 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 +4 -3
- investing_algorithm_framework/app/web/controllers/portfolio.py +1 -1
- investing_algorithm_framework/app/web/controllers/positions.py +3 -3
- investing_algorithm_framework/app/web/create_app.py +4 -2
- investing_algorithm_framework/app/web/error_handler.py +1 -1
- investing_algorithm_framework/app/web/schemas/order.py +2 -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 +43 -9
- investing_algorithm_framework/dependency_container.py +121 -33
- investing_algorithm_framework/domain/__init__.py +109 -22
- 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 +60 -138
- investing_algorithm_framework/domain/constants.py +23 -34
- 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 +51 -1
- investing_algorithm_framework/domain/models/__init__.py +29 -14
- investing_algorithm_framework/domain/models/app_mode.py +34 -0
- investing_algorithm_framework/domain/models/base_model.py +3 -1
- 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 +243 -86
- 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 +7 -2
- investing_algorithm_framework/domain/models/portfolio/portfolio.py +134 -1
- investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +37 -37
- investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +208 -0
- investing_algorithm_framework/domain/models/position/__init__.py +3 -2
- investing_algorithm_framework/domain/models/position/position.py +29 -0
- investing_algorithm_framework/domain/models/position/position_size.py +41 -0
- investing_algorithm_framework/domain/models/position/{position_cost.py → position_snapshot.py} +16 -8
- 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 +33 -0
- 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 +111 -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 +16 -4
- 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 +39 -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 +87 -13
- investing_algorithm_framework/infrastructure/models/__init__.py +13 -4
- investing_algorithm_framework/infrastructure/models/decimal_parser.py +14 -0
- investing_algorithm_framework/infrastructure/models/order/__init__.py +2 -2
- investing_algorithm_framework/infrastructure/models/order/order.py +73 -73
- 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 +3 -2
- investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +37 -0
- investing_algorithm_framework/infrastructure/models/portfolio/{portfolio.py → sql_portfolio.py} +57 -3
- investing_algorithm_framework/infrastructure/models/position/__init__.py +2 -2
- investing_algorithm_framework/infrastructure/models/position/position.py +16 -11
- 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 +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 +13 -5
- investing_algorithm_framework/infrastructure/repositories/order_metadata_repository.py +17 -0
- investing_algorithm_framework/infrastructure/repositories/order_repository.py +32 -19
- investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +2 -2
- investing_algorithm_framework/infrastructure/repositories/portfolio_snapshot_repository.py +56 -0
- investing_algorithm_framework/infrastructure/repositories/position_repository.py +47 -4
- investing_algorithm_framework/infrastructure/repositories/position_snapshot_repository.py +21 -0
- investing_algorithm_framework/infrastructure/repositories/repository.py +85 -31
- 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 -2
- 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 +127 -10
- investing_algorithm_framework/services/configuration_service.py +95 -0
- 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/positions/position_snapshot_service.py +18 -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.3.1.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 -410
- 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 -76
- 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/trading_data_types.py +0 -47
- investing_algorithm_framework/domain/models/trading_time_frame.py +0 -205
- investing_algorithm_framework/domain/singleton.py +0 -9
- investing_algorithm_framework/infrastructure/models/order/order_fee.py +0 -21
- investing_algorithm_framework/infrastructure/models/position/position_cost.py +0 -32
- investing_algorithm_framework/infrastructure/repositories/order_fee_repository.py +0 -15
- investing_algorithm_framework/infrastructure/repositories/position_cost_repository.py +0 -16
- investing_algorithm_framework/infrastructure/services/market_service.py +0 -422
- investing_algorithm_framework/services/market_data_service.py +0 -75
- investing_algorithm_framework/services/order_service.py +0 -464
- investing_algorithm_framework/services/portfolio_service.py +0 -105
- investing_algorithm_framework/services/position_cost_service.py +0 -5
- investing_algorithm_framework/services/position_service.py +0 -50
- investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -219
- investing_algorithm_framework/setup_logging.py +0 -40
- investing_algorithm_framework-1.3.1.dist-info/AUTHORS.md +0 -8
- investing_algorithm_framework-1.3.1.dist-info/METADATA +0 -172
- investing_algorithm_framework-1.3.1.dist-info/RECORD +0 -103
- investing_algorithm_framework-1.3.1.dist-info/top_level.txt +0 -1
- {investing_algorithm_framework-1.3.1.dist-info → investing_algorithm_framework-7.25.6.dist-info}/LICENSE +0 -0
|
@@ -1,39 +1,48 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from datetime import datetime
|
|
2
|
+
from datetime import datetime, timezone
|
|
3
|
+
|
|
4
|
+
from dateutil.parser import parse
|
|
5
|
+
|
|
3
6
|
from investing_algorithm_framework.domain.exceptions import \
|
|
4
7
|
OperationalException
|
|
5
8
|
from investing_algorithm_framework.domain.models.base_model import BaseModel
|
|
6
|
-
from investing_algorithm_framework.domain.models.order import
|
|
7
|
-
|
|
8
|
-
from investing_algorithm_framework.domain.models.order.
|
|
9
|
-
|
|
9
|
+
from investing_algorithm_framework.domain.models.order.order_side import \
|
|
10
|
+
OrderSide
|
|
11
|
+
from investing_algorithm_framework.domain.models.order.order_status import \
|
|
12
|
+
OrderStatus
|
|
13
|
+
from investing_algorithm_framework.domain.models.order.order_type import \
|
|
14
|
+
OrderType
|
|
10
15
|
|
|
11
|
-
logger = logging.getLogger(
|
|
16
|
+
logger = logging.getLogger("investing_algorithm_framework")
|
|
12
17
|
|
|
13
18
|
|
|
14
19
|
class Order(BaseModel):
|
|
15
|
-
|
|
20
|
+
"""
|
|
21
|
+
Order model class to represent an order of the trading bot
|
|
22
|
+
"""
|
|
16
23
|
def __init__(
|
|
17
24
|
self,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
status,
|
|
25
|
+
order_type,
|
|
26
|
+
order_side,
|
|
21
27
|
amount,
|
|
28
|
+
status: OrderStatus | None | str = OrderStatus.CREATED.value,
|
|
22
29
|
target_symbol=None,
|
|
23
30
|
trading_symbol=None,
|
|
24
31
|
price=None,
|
|
25
|
-
net_gain=0,
|
|
26
32
|
created_at=None,
|
|
27
33
|
updated_at=None,
|
|
28
|
-
trade_closed_at=None,
|
|
29
|
-
trade_closed_price=None,
|
|
30
34
|
external_id=None,
|
|
31
|
-
filled_amount=None,
|
|
32
|
-
remaining_amount=None,
|
|
33
35
|
cost=None,
|
|
36
|
+
filled=None,
|
|
37
|
+
remaining=None,
|
|
34
38
|
fee=None,
|
|
39
|
+
position_id=None,
|
|
40
|
+
order_fee=None,
|
|
41
|
+
order_fee_currency=None,
|
|
42
|
+
order_fee_rate=None,
|
|
43
|
+
id=None,
|
|
44
|
+
metadata=None,
|
|
35
45
|
):
|
|
36
|
-
|
|
37
46
|
if target_symbol is None:
|
|
38
47
|
raise OperationalException("Target symbol is not specified")
|
|
39
48
|
|
|
@@ -43,30 +52,44 @@ class Order(BaseModel):
|
|
|
43
52
|
self.target_symbol = target_symbol.upper()
|
|
44
53
|
self.trading_symbol = trading_symbol.upper()
|
|
45
54
|
|
|
46
|
-
if
|
|
55
|
+
if order_side is None:
|
|
47
56
|
raise OperationalException("Order side is not set")
|
|
48
57
|
|
|
49
|
-
if
|
|
58
|
+
if order_type is None:
|
|
50
59
|
raise OperationalException("Order type is not set")
|
|
51
60
|
|
|
52
61
|
if status is None:
|
|
53
62
|
raise OperationalException("Status is not set")
|
|
54
63
|
|
|
64
|
+
self.created_at = created_at
|
|
65
|
+
self.updated_at = updated_at
|
|
66
|
+
|
|
67
|
+
if self.created_at is None:
|
|
68
|
+
self.created_at = datetime.now(tz=timezone.utc)
|
|
69
|
+
|
|
70
|
+
if self.updated_at is None:
|
|
71
|
+
self.updated_at = datetime.now(tz=timezone.utc)
|
|
72
|
+
|
|
55
73
|
self.external_id = external_id
|
|
56
74
|
self.price = price
|
|
57
|
-
self.
|
|
58
|
-
self.
|
|
75
|
+
self.order_side = OrderSide.from_value(order_side).value
|
|
76
|
+
self.order_type = OrderType.from_value(order_type).value
|
|
59
77
|
self.status = OrderStatus.from_value(status).value
|
|
78
|
+
self.position_id = position_id
|
|
60
79
|
self.amount = amount
|
|
61
|
-
self.
|
|
62
|
-
self.
|
|
63
|
-
self.trade_closed_price = trade_closed_price
|
|
64
|
-
self.created_at = created_at
|
|
65
|
-
self.updated_at = updated_at
|
|
66
|
-
self.filled_amount = filled_amount
|
|
67
|
-
self.remaining_amount = remaining_amount
|
|
68
|
-
self.cost = cost
|
|
80
|
+
self.filled = filled
|
|
81
|
+
self.remaining = remaining
|
|
69
82
|
self.fee = fee
|
|
83
|
+
self._available_amount = self.filled
|
|
84
|
+
self.order_fee = order_fee
|
|
85
|
+
self.order_fee_currency = order_fee_currency
|
|
86
|
+
self.order_fee_rate = order_fee_rate
|
|
87
|
+
self.id = id
|
|
88
|
+
self.cost = cost
|
|
89
|
+
self.metadata = metadata if metadata is not None else {}
|
|
90
|
+
|
|
91
|
+
def get_id(self):
|
|
92
|
+
return self.id
|
|
70
93
|
|
|
71
94
|
def get_external_id(self):
|
|
72
95
|
return self.external_id
|
|
@@ -86,8 +109,26 @@ class Order(BaseModel):
|
|
|
86
109
|
def set_price(self, price):
|
|
87
110
|
self.price = price
|
|
88
111
|
|
|
89
|
-
def
|
|
90
|
-
return self.
|
|
112
|
+
def get_order_fee_currency(self):
|
|
113
|
+
return self.order_fee_currency
|
|
114
|
+
|
|
115
|
+
def set_order_fee_currency(self, order_fee_currency):
|
|
116
|
+
self.order_fee_currency = order_fee_currency
|
|
117
|
+
|
|
118
|
+
def get_order_fee_rate(self):
|
|
119
|
+
return self.order_fee_rate
|
|
120
|
+
|
|
121
|
+
def set_order_fee_rate(self, order_fee_rate):
|
|
122
|
+
self.order_fee_rate = order_fee_rate
|
|
123
|
+
|
|
124
|
+
def get_order_fee(self):
|
|
125
|
+
return self.order_fee
|
|
126
|
+
|
|
127
|
+
def set_order_fee(self, order_fee):
|
|
128
|
+
self.order_fee = order_fee
|
|
129
|
+
|
|
130
|
+
def get_order_size(self):
|
|
131
|
+
return self.order_side
|
|
91
132
|
|
|
92
133
|
def get_status(self) -> OrderStatus:
|
|
93
134
|
return self.status
|
|
@@ -95,8 +136,11 @@ class Order(BaseModel):
|
|
|
95
136
|
def set_status(self, status):
|
|
96
137
|
self.status = OrderStatus.from_value(status).value
|
|
97
138
|
|
|
98
|
-
def
|
|
99
|
-
return self.
|
|
139
|
+
def get_order_type(self):
|
|
140
|
+
return self.order_type
|
|
141
|
+
|
|
142
|
+
def get_order_side(self):
|
|
143
|
+
return self.order_side
|
|
100
144
|
|
|
101
145
|
def get_amount(self):
|
|
102
146
|
return self.amount
|
|
@@ -107,24 +151,6 @@ class Order(BaseModel):
|
|
|
107
151
|
def set_external_id(self, external_id):
|
|
108
152
|
self.external_id = external_id
|
|
109
153
|
|
|
110
|
-
def get_net_gain(self):
|
|
111
|
-
return self.net_gain
|
|
112
|
-
|
|
113
|
-
def set_net_gain(self, net_gain):
|
|
114
|
-
self.net_gain = net_gain
|
|
115
|
-
|
|
116
|
-
def get_trade_closed_at(self):
|
|
117
|
-
return self.trade_closed_at
|
|
118
|
-
|
|
119
|
-
def set_trade_closed_at(self, trade_closed_at):
|
|
120
|
-
self.trade_closed_at = trade_closed_at
|
|
121
|
-
|
|
122
|
-
def get_trade_closed_price(self):
|
|
123
|
-
return self.trade_closed_price
|
|
124
|
-
|
|
125
|
-
def set_trade_closed_price(self, trade_closed_price):
|
|
126
|
-
self.trade_closed_price = trade_closed_price
|
|
127
|
-
|
|
128
154
|
def get_created_at(self):
|
|
129
155
|
return self.created_at
|
|
130
156
|
|
|
@@ -137,23 +163,25 @@ class Order(BaseModel):
|
|
|
137
163
|
def set_updated_at(self, updated_at):
|
|
138
164
|
self.updated_at = updated_at
|
|
139
165
|
|
|
140
|
-
def
|
|
141
|
-
return self.filled_amount
|
|
166
|
+
def get_filled(self):
|
|
142
167
|
|
|
143
|
-
|
|
144
|
-
|
|
168
|
+
if self.filled is None:
|
|
169
|
+
return 0
|
|
145
170
|
|
|
146
|
-
|
|
147
|
-
return self.remaining_amount
|
|
171
|
+
return self.filled
|
|
148
172
|
|
|
149
|
-
def
|
|
150
|
-
self.
|
|
173
|
+
def set_filled(self, filled):
|
|
174
|
+
self.filled = filled
|
|
151
175
|
|
|
152
|
-
def
|
|
153
|
-
return self.cost
|
|
176
|
+
def get_remaining(self):
|
|
154
177
|
|
|
155
|
-
|
|
156
|
-
|
|
178
|
+
if self.remaining is None:
|
|
179
|
+
return self.get_amount() - self.get_filled()
|
|
180
|
+
|
|
181
|
+
return self.remaining
|
|
182
|
+
|
|
183
|
+
def set_remaining(self, remaining):
|
|
184
|
+
self.remaining = remaining
|
|
157
185
|
|
|
158
186
|
def get_fee(self):
|
|
159
187
|
return self.fee
|
|
@@ -161,32 +189,148 @@ class Order(BaseModel):
|
|
|
161
189
|
def set_fee(self, order_fee):
|
|
162
190
|
self.fee = order_fee
|
|
163
191
|
|
|
164
|
-
def
|
|
192
|
+
def get_symbol(self):
|
|
193
|
+
return (self.get_target_symbol().upper() + "/"
|
|
194
|
+
+ self.get_trading_symbol().upper())
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
def symbol(self):
|
|
198
|
+
return (self.get_target_symbol().upper() + "/"
|
|
199
|
+
+ self.get_trading_symbol().upper())
|
|
200
|
+
|
|
201
|
+
def get_available_amount(self):
|
|
202
|
+
|
|
203
|
+
if self._available_amount is None:
|
|
204
|
+
return self.get_filled()
|
|
205
|
+
|
|
206
|
+
return self._available_amount
|
|
207
|
+
|
|
208
|
+
@property
|
|
209
|
+
def available_amount(self):
|
|
210
|
+
return self.get_available_amount()
|
|
211
|
+
|
|
212
|
+
def set_available_amount(self, available_amount):
|
|
213
|
+
self._available_amount = available_amount
|
|
214
|
+
|
|
215
|
+
@available_amount.setter
|
|
216
|
+
def available_amount(self, available_amount):
|
|
217
|
+
self.set_available_amount(available_amount)
|
|
218
|
+
|
|
219
|
+
def to_dict(self, datetime_format=None):
|
|
220
|
+
"""
|
|
221
|
+
Convert the Order object to a dictionary
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
datetime_format (str): The format to use for the datetime fields.
|
|
225
|
+
If None, the datetime fields will be returned as is.
|
|
226
|
+
Defaults to None.
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
dict: A dictionary representation of the Order object.
|
|
230
|
+
"""
|
|
231
|
+
|
|
232
|
+
def ensure_iso(value):
|
|
233
|
+
if hasattr(value, "isoformat"):
|
|
234
|
+
if value.tzinfo is None:
|
|
235
|
+
value = value.replace(tzinfo=timezone.utc)
|
|
236
|
+
return value.isoformat()
|
|
237
|
+
return value
|
|
238
|
+
|
|
239
|
+
created_at = ensure_iso(self.created_at) if self.created_at else None
|
|
240
|
+
updated_at = ensure_iso(self.updated_at) if self.updated_at else None
|
|
241
|
+
|
|
242
|
+
# Ensure status is a string
|
|
243
|
+
self.status = OrderStatus.from_value(self.status).value
|
|
244
|
+
|
|
165
245
|
return {
|
|
246
|
+
"id": self.id,
|
|
166
247
|
"external_id": self.external_id,
|
|
167
248
|
"target_symbol": self.target_symbol,
|
|
168
249
|
"trading_symbol": self.trading_symbol,
|
|
169
|
-
"
|
|
170
|
-
"
|
|
250
|
+
"order_side": self.order_side,
|
|
251
|
+
"order_type": self.order_type,
|
|
171
252
|
"status": self.status,
|
|
172
253
|
"price": self.price,
|
|
173
254
|
"amount": self.amount,
|
|
174
|
-
"
|
|
175
|
-
"
|
|
176
|
-
"trade_closed_price": self.trade_closed_price,
|
|
177
|
-
"created_at": self.created_at,
|
|
178
|
-
"updated_at": self.updated_at,
|
|
179
|
-
"filled_amount": self.filled_amount,
|
|
180
|
-
"remaining_amount": self.remaining_amount,
|
|
255
|
+
"created_at": created_at,
|
|
256
|
+
"updated_at": updated_at,
|
|
181
257
|
"cost": self.cost,
|
|
182
|
-
"
|
|
258
|
+
"filled": self.filled,
|
|
259
|
+
"remaining": self.remaining,
|
|
260
|
+
"order_fee_currency": self.order_fee_currency,
|
|
261
|
+
"order_fee_rate": self.order_fee_rate,
|
|
262
|
+
"order_fee": self.order_fee,
|
|
263
|
+
"metadata": self.metadata if hasattr(self, 'metadata') else {},
|
|
183
264
|
}
|
|
184
265
|
|
|
266
|
+
@staticmethod
|
|
267
|
+
def from_dict(data: dict):
|
|
268
|
+
created_at = data.get("created_at", None)
|
|
269
|
+
updated_at = data.get("updated_at", None)
|
|
270
|
+
symbol = data.get("symbol", None)
|
|
271
|
+
|
|
272
|
+
if symbol is not None:
|
|
273
|
+
target_symbol = symbol.split("/")[0]
|
|
274
|
+
trading_symbol = symbol.split("/")[1]
|
|
275
|
+
else:
|
|
276
|
+
target_symbol = data.get("target_symbol", None)
|
|
277
|
+
trading_symbol = data.get("trading_symbol", None)
|
|
278
|
+
|
|
279
|
+
if created_at is not None:
|
|
280
|
+
created_at = parse(created_at)
|
|
281
|
+
|
|
282
|
+
if updated_at is not None:
|
|
283
|
+
updated_at = parse(updated_at)
|
|
284
|
+
|
|
285
|
+
order = Order(
|
|
286
|
+
id=data.get("id", None),
|
|
287
|
+
external_id=data.get("external_id", None),
|
|
288
|
+
target_symbol=target_symbol,
|
|
289
|
+
trading_symbol=trading_symbol,
|
|
290
|
+
price=data.get("price", None),
|
|
291
|
+
amount=data.get("amount", None),
|
|
292
|
+
status=data.get("status", None),
|
|
293
|
+
order_type=data.get("order_type", None),
|
|
294
|
+
order_side=data.get("order_side", None),
|
|
295
|
+
filled=data.get("filled", None),
|
|
296
|
+
remaining=data.get("remaining", None),
|
|
297
|
+
fee=data.get("fee", None),
|
|
298
|
+
cost=data.get("cost", None),
|
|
299
|
+
created_at=created_at,
|
|
300
|
+
updated_at=updated_at,
|
|
301
|
+
order_fee=data.get("order_fee", None),
|
|
302
|
+
order_fee_currency=data.get("order_fee_currency", None),
|
|
303
|
+
order_fee_rate=data.get("order_fee_rate", None),
|
|
304
|
+
metadata=data.get("metadata", {}),
|
|
305
|
+
)
|
|
306
|
+
return order
|
|
307
|
+
|
|
185
308
|
@staticmethod
|
|
186
309
|
def from_ccxt_order(ccxt_order):
|
|
310
|
+
"""
|
|
311
|
+
Create an Order object from a ccxt order object
|
|
312
|
+
:param ccxt_order: ccxt order object
|
|
313
|
+
:return: Order object
|
|
314
|
+
"""
|
|
187
315
|
status = OrderStatus.from_value(ccxt_order["status"])
|
|
188
316
|
target_symbol = ccxt_order.get("symbol").split("/")[0]
|
|
189
317
|
trading_symbol = ccxt_order.get("symbol").split("/")[1]
|
|
318
|
+
ccxt_fee = ccxt_order.get("fee", None)
|
|
319
|
+
order_fee = None
|
|
320
|
+
order_fee_currency = None
|
|
321
|
+
order_fee_rate = None
|
|
322
|
+
|
|
323
|
+
if ccxt_fee is not None:
|
|
324
|
+
order_fee = ccxt_fee.get("cost", None)
|
|
325
|
+
order_fee_currency = ccxt_fee.get("currency", None)
|
|
326
|
+
order_fee_rate = ccxt_fee.get("rate", None)
|
|
327
|
+
|
|
328
|
+
created_at = ccxt_order.get("datetime", None)
|
|
329
|
+
created_at = parse(created_at) if created_at else None
|
|
330
|
+
|
|
331
|
+
# Make sure that the created_at is a utc datetime object
|
|
332
|
+
if created_at and created_at.tzinfo is None:
|
|
333
|
+
created_at = created_at.replace(tzinfo=timezone.utc)
|
|
190
334
|
|
|
191
335
|
return Order(
|
|
192
336
|
external_id=ccxt_order.get("id", None),
|
|
@@ -195,13 +339,15 @@ class Order(BaseModel):
|
|
|
195
339
|
price=ccxt_order.get("price", None),
|
|
196
340
|
amount=ccxt_order.get("amount", None),
|
|
197
341
|
status=status,
|
|
198
|
-
type=ccxt_order.get("type", None),
|
|
199
|
-
side=ccxt_order.get("side", None),
|
|
200
|
-
filled_amount=ccxt_order.get("filled", None),
|
|
201
|
-
remaining_amount=ccxt_order.get("remaining", None),
|
|
202
342
|
cost=ccxt_order.get("cost", None),
|
|
203
|
-
|
|
204
|
-
|
|
343
|
+
order_type=ccxt_order.get("type", None),
|
|
344
|
+
order_side=ccxt_order.get("side", None),
|
|
345
|
+
filled=ccxt_order.get("filled", None),
|
|
346
|
+
remaining=ccxt_order.get("remaining", None),
|
|
347
|
+
order_fee=order_fee,
|
|
348
|
+
order_fee_currency=order_fee_currency,
|
|
349
|
+
order_fee_rate=order_fee_rate,
|
|
350
|
+
created_at=created_at
|
|
205
351
|
)
|
|
206
352
|
|
|
207
353
|
def __repr__(self):
|
|
@@ -213,15 +359,26 @@ class Order(BaseModel):
|
|
|
213
359
|
|
|
214
360
|
return self.repr(
|
|
215
361
|
id=id_value,
|
|
362
|
+
price=self.get_price(),
|
|
363
|
+
amount=self.get_amount(),
|
|
216
364
|
external_id=self.external_id,
|
|
217
365
|
status=self.status,
|
|
218
366
|
target_symbol=self.target_symbol,
|
|
219
367
|
trading_symbol=self.trading_symbol,
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
cost=self.cost,
|
|
368
|
+
order_side=self.order_side,
|
|
369
|
+
order_type=self.order_type,
|
|
370
|
+
filled=self.get_filled(),
|
|
371
|
+
remaining=self.get_remaining(),
|
|
372
|
+
created_at=self.get_created_at(),
|
|
373
|
+
updated_at=self.get_updated_at(),
|
|
227
374
|
)
|
|
375
|
+
|
|
376
|
+
def get_size(self):
|
|
377
|
+
"""
|
|
378
|
+
Get the size of the order
|
|
379
|
+
|
|
380
|
+
Returns:
|
|
381
|
+
float: The size of the order
|
|
382
|
+
"""
|
|
383
|
+
return self.get_amount() * self.get_price() \
|
|
384
|
+
if self.get_price() is not None else 0
|
|
@@ -18,7 +18,7 @@ class OrderStatus(Enum):
|
|
|
18
18
|
if value.upper() == order_type.value:
|
|
19
19
|
return order_type
|
|
20
20
|
|
|
21
|
-
raise ValueError("Could not convert value to OrderStatus")
|
|
21
|
+
raise ValueError(f"Could not convert value {value} to OrderStatus")
|
|
22
22
|
|
|
23
23
|
@staticmethod
|
|
24
24
|
def from_value(value):
|
|
@@ -31,7 +31,7 @@ class OrderStatus(Enum):
|
|
|
31
31
|
elif isinstance(value, str):
|
|
32
32
|
return OrderStatus.from_string(value)
|
|
33
33
|
|
|
34
|
-
raise ValueError("Could not convert value to OrderStatus")
|
|
34
|
+
raise ValueError(f"Could not convert value: {value} to OrderStatus")
|
|
35
35
|
|
|
36
36
|
def equals(self, other):
|
|
37
37
|
return OrderStatus.from_value(other) == self
|
|
@@ -3,8 +3,6 @@ from enum import Enum
|
|
|
3
3
|
|
|
4
4
|
class OrderType(Enum):
|
|
5
5
|
LIMIT = 'LIMIT'
|
|
6
|
-
MARKET = 'MARKET'
|
|
7
|
-
STOP_LOSS_LIMIT = "STOP_LOSS_LIMIT"
|
|
8
6
|
|
|
9
7
|
@staticmethod
|
|
10
8
|
def from_string(value: str):
|
|
@@ -15,7 +13,7 @@ class OrderType(Enum):
|
|
|
15
13
|
if value.upper() == order_type.value:
|
|
16
14
|
return order_type
|
|
17
15
|
|
|
18
|
-
raise ValueError("Could not convert value to OrderType")
|
|
16
|
+
raise ValueError(f"Could not convert value: {value} to OrderType")
|
|
19
17
|
|
|
20
18
|
@staticmethod
|
|
21
19
|
def from_value(value):
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
from .portfolio_configuration import PortfolioConfiguration
|
|
2
1
|
from .portfolio import Portfolio
|
|
2
|
+
from .portfolio_configuration import PortfolioConfiguration
|
|
3
|
+
from .portfolio_snapshot import PortfolioSnapshot
|
|
3
4
|
|
|
4
|
-
__all__ = [
|
|
5
|
+
__all__ = [
|
|
6
|
+
"PortfolioConfiguration",
|
|
7
|
+
"Portfolio",
|
|
8
|
+
"PortfolioSnapshot",
|
|
9
|
+
]
|
|
@@ -2,6 +2,37 @@ from investing_algorithm_framework.domain.models.base_model import BaseModel
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class Portfolio(BaseModel):
|
|
5
|
+
"""
|
|
6
|
+
Portfolio base class.
|
|
7
|
+
|
|
8
|
+
A portfolio is a collection of positions that are managed by an algorithm.
|
|
9
|
+
|
|
10
|
+
Attributes:
|
|
11
|
+
* identifier: str, unique identifier of the portfolio
|
|
12
|
+
* trading_symbol: str, trading symbol of the portfolio
|
|
13
|
+
* unallocated: float, the size of the trading symbol that is not
|
|
14
|
+
allocated. For example, if the trading symbol is USDT and the unallocated
|
|
15
|
+
is 1000, it means that the portfolio has 1000 USDT that is not
|
|
16
|
+
allocated to any position.
|
|
17
|
+
* net_size: float, net size of the portfolio is the initial balance of the
|
|
18
|
+
portfolio plus the all the net gains of the trades. The
|
|
19
|
+
* realized: float, the realized gain of the portfolio is the sum of all the
|
|
20
|
+
realized gains of the trades.
|
|
21
|
+
* total_revenue: float, the total revenue of the portfolio is the sum
|
|
22
|
+
of all the orders (price * size)
|
|
23
|
+
* total_cost: float, the total cost of the portfolio is the sum of all the
|
|
24
|
+
costs of the trades (price * size (for buy orders)
|
|
25
|
+
or -price * size (for sell orders))
|
|
26
|
+
* total_net_gain: float, the total net gain of the portfolio is the sum of
|
|
27
|
+
all the net gains of the trades
|
|
28
|
+
* total_trade_volume: float, the total trade volume of the
|
|
29
|
+
portfolio is the sum of all the sizes of the trades
|
|
30
|
+
* market: str, the market of the portfolio (e.g. BITVAVO, BINANCE)
|
|
31
|
+
* created_at: datetime, the datetime when the portfolio was created
|
|
32
|
+
* updated_at: datetime, the datetime when the portfolio was last updated
|
|
33
|
+
* initialized: bool, whether the portfolio is initialized or not
|
|
34
|
+
* initial_balance: float, the initial balance of the portfolio
|
|
35
|
+
"""
|
|
5
36
|
|
|
6
37
|
def __init__(
|
|
7
38
|
self,
|
|
@@ -9,20 +40,33 @@ class Portfolio(BaseModel):
|
|
|
9
40
|
trading_symbol,
|
|
10
41
|
net_size,
|
|
11
42
|
unallocated,
|
|
43
|
+
initial_balance,
|
|
44
|
+
market,
|
|
12
45
|
realized=0,
|
|
13
46
|
total_revenue=0,
|
|
14
47
|
total_cost=0,
|
|
15
48
|
total_net_gain=0,
|
|
49
|
+
total_trade_volume=0,
|
|
50
|
+
created_at=None,
|
|
51
|
+
updated_at=None,
|
|
52
|
+
initialized=False,
|
|
16
53
|
):
|
|
17
54
|
self.identifier = identifier
|
|
18
55
|
self.updated_at = None
|
|
19
56
|
self.trading_symbol = trading_symbol.upper()
|
|
20
57
|
self.net_size = net_size
|
|
21
58
|
self.unallocated = unallocated
|
|
59
|
+
self.initial_balance = initial_balance
|
|
22
60
|
self.realized = realized
|
|
23
61
|
self.total_revenue = total_revenue
|
|
24
62
|
self.total_cost = total_cost
|
|
25
63
|
self.total_net_gain = total_net_gain
|
|
64
|
+
self.total_trade_volume = total_trade_volume
|
|
65
|
+
self.market = market.upper()
|
|
66
|
+
self.created_at = created_at
|
|
67
|
+
self.updated_at = updated_at
|
|
68
|
+
self.initialized = initialized
|
|
69
|
+
self._allocated = None
|
|
26
70
|
|
|
27
71
|
def __repr__(self):
|
|
28
72
|
return self.repr(
|
|
@@ -32,5 +76,94 @@ class Portfolio(BaseModel):
|
|
|
32
76
|
unallocated=self.unallocated,
|
|
33
77
|
realized=self.realized,
|
|
34
78
|
total_revenue=self.total_revenue,
|
|
35
|
-
total_cost=self.total_cost
|
|
79
|
+
total_cost=self.total_cost,
|
|
80
|
+
market=self.market,
|
|
81
|
+
initial_balance=self.initial_balance
|
|
36
82
|
)
|
|
83
|
+
|
|
84
|
+
def get_identifier(self):
|
|
85
|
+
return self.identifier
|
|
86
|
+
|
|
87
|
+
def get_unallocated(self):
|
|
88
|
+
return self.unallocated
|
|
89
|
+
|
|
90
|
+
def get_net_size(self):
|
|
91
|
+
return self.net_size
|
|
92
|
+
|
|
93
|
+
def get_realized(self):
|
|
94
|
+
return self.realized
|
|
95
|
+
|
|
96
|
+
def get_total_revenue(self):
|
|
97
|
+
return self.total_revenue
|
|
98
|
+
|
|
99
|
+
def get_total_cost(self):
|
|
100
|
+
return self.total_cost
|
|
101
|
+
|
|
102
|
+
def get_total_net_gain(self):
|
|
103
|
+
return self.total_net_gain
|
|
104
|
+
|
|
105
|
+
def get_total_trade_volume(self):
|
|
106
|
+
return self.total_trade_volume
|
|
107
|
+
|
|
108
|
+
def get_created_at(self):
|
|
109
|
+
return self.created_at
|
|
110
|
+
|
|
111
|
+
def get_updated_at(self):
|
|
112
|
+
return self.updated_at
|
|
113
|
+
|
|
114
|
+
def get_trading_symbol(self):
|
|
115
|
+
return self.trading_symbol
|
|
116
|
+
|
|
117
|
+
def get_market(self):
|
|
118
|
+
return self.market
|
|
119
|
+
|
|
120
|
+
def get_initial_balance(self):
|
|
121
|
+
return self.initial_balance
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def allocated(self):
|
|
125
|
+
|
|
126
|
+
if self._allocated is None:
|
|
127
|
+
return 0.0
|
|
128
|
+
|
|
129
|
+
return self._allocated
|
|
130
|
+
|
|
131
|
+
@allocated.setter
|
|
132
|
+
def allocated(self, value):
|
|
133
|
+
self._allocated = value
|
|
134
|
+
|
|
135
|
+
@staticmethod
|
|
136
|
+
def from_portfolio_configuration(portfolio_configuration):
|
|
137
|
+
"""
|
|
138
|
+
Function to create a portfolio from a portfolio configuration
|
|
139
|
+
|
|
140
|
+
We assume that a portfolio that is created from a configuration
|
|
141
|
+
is always un initialized.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
portfolio_configuration: PortfolioConfiguration
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
Portfolio
|
|
148
|
+
"""
|
|
149
|
+
return Portfolio(
|
|
150
|
+
identifier=portfolio_configuration.identifier,
|
|
151
|
+
trading_symbol=portfolio_configuration.trading_symbol,
|
|
152
|
+
unallocated=portfolio_configuration.initial_balance,
|
|
153
|
+
net_size=portfolio_configuration.initial_balance,
|
|
154
|
+
market=portfolio_configuration.market,
|
|
155
|
+
initial_balance=portfolio_configuration.initial_balance,
|
|
156
|
+
initialized=False
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
def to_dict(self):
|
|
160
|
+
return {
|
|
161
|
+
"trading_symbol": self.trading_symbol,
|
|
162
|
+
"market": self.market,
|
|
163
|
+
"unallocated": self.unallocated,
|
|
164
|
+
"identifier": self.identifier,
|
|
165
|
+
"created_at": self.created_at,
|
|
166
|
+
"updated_at": self.updated_at,
|
|
167
|
+
"initialized": self.initialized,
|
|
168
|
+
"initial_balance": self.initial_balance,
|
|
169
|
+
}
|