investing-algorithm-framework 1.5__py3-none-any.whl → 7.25.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- investing_algorithm_framework/__init__.py +192 -16
- investing_algorithm_framework/analysis/__init__.py +16 -0
- investing_algorithm_framework/analysis/backtest_data_ranges.py +202 -0
- investing_algorithm_framework/analysis/data.py +170 -0
- investing_algorithm_framework/analysis/markdown.py +91 -0
- investing_algorithm_framework/analysis/ranking.py +298 -0
- investing_algorithm_framework/app/__init__.py +29 -4
- investing_algorithm_framework/app/algorithm/__init__.py +7 -0
- investing_algorithm_framework/app/algorithm/algorithm.py +193 -0
- investing_algorithm_framework/app/algorithm/algorithm_factory.py +118 -0
- investing_algorithm_framework/app/app.py +2220 -379
- investing_algorithm_framework/app/app_hook.py +28 -0
- investing_algorithm_framework/app/context.py +1724 -0
- investing_algorithm_framework/app/eventloop.py +620 -0
- investing_algorithm_framework/app/reporting/__init__.py +27 -0
- investing_algorithm_framework/app/reporting/ascii.py +921 -0
- investing_algorithm_framework/app/reporting/backtest_report.py +349 -0
- investing_algorithm_framework/app/reporting/charts/__init__.py +19 -0
- investing_algorithm_framework/app/reporting/charts/entry_exist_signals.py +66 -0
- investing_algorithm_framework/app/reporting/charts/equity_curve.py +37 -0
- investing_algorithm_framework/app/reporting/charts/equity_curve_drawdown.py +74 -0
- investing_algorithm_framework/app/reporting/charts/line_chart.py +11 -0
- investing_algorithm_framework/app/reporting/charts/monthly_returns_heatmap.py +70 -0
- investing_algorithm_framework/app/reporting/charts/ohlcv_data_completeness.py +51 -0
- investing_algorithm_framework/app/reporting/charts/rolling_sharp_ratio.py +79 -0
- investing_algorithm_framework/app/reporting/charts/yearly_returns_barchart.py +55 -0
- investing_algorithm_framework/app/reporting/generate.py +185 -0
- investing_algorithm_framework/app/reporting/tables/__init__.py +11 -0
- investing_algorithm_framework/app/reporting/tables/key_metrics_table.py +217 -0
- investing_algorithm_framework/app/reporting/tables/time_metrics_table.py +80 -0
- investing_algorithm_framework/app/reporting/tables/trade_metrics_table.py +147 -0
- investing_algorithm_framework/app/reporting/tables/trades_table.py +75 -0
- investing_algorithm_framework/app/reporting/tables/utils.py +29 -0
- investing_algorithm_framework/app/reporting/templates/report_template.html.j2 +154 -0
- investing_algorithm_framework/app/stateless/action_handlers/__init__.py +6 -3
- investing_algorithm_framework/app/stateless/action_handlers/action_handler_strategy.py +1 -1
- investing_algorithm_framework/app/stateless/action_handlers/check_online_handler.py +2 -1
- investing_algorithm_framework/app/stateless/action_handlers/run_strategy_handler.py +14 -7
- investing_algorithm_framework/app/strategy.py +867 -60
- investing_algorithm_framework/app/task.py +5 -3
- investing_algorithm_framework/app/web/__init__.py +2 -1
- investing_algorithm_framework/app/web/controllers/__init__.py +2 -2
- investing_algorithm_framework/app/web/controllers/orders.py +3 -2
- investing_algorithm_framework/app/web/controllers/positions.py +2 -2
- investing_algorithm_framework/app/web/create_app.py +4 -2
- investing_algorithm_framework/app/web/schemas/position.py +1 -0
- investing_algorithm_framework/cli/__init__.py +0 -0
- investing_algorithm_framework/cli/cli.py +231 -0
- investing_algorithm_framework/cli/deploy_to_aws_lambda.py +501 -0
- investing_algorithm_framework/cli/deploy_to_azure_function.py +718 -0
- investing_algorithm_framework/cli/initialize_app.py +603 -0
- investing_algorithm_framework/cli/templates/.gitignore.template +178 -0
- investing_algorithm_framework/cli/templates/app.py.template +18 -0
- investing_algorithm_framework/cli/templates/app_aws_lambda_function.py.template +48 -0
- investing_algorithm_framework/cli/templates/app_azure_function.py.template +14 -0
- investing_algorithm_framework/cli/templates/app_web.py.template +18 -0
- investing_algorithm_framework/cli/templates/aws_lambda_dockerfile.template +22 -0
- investing_algorithm_framework/cli/templates/aws_lambda_dockerignore.template +92 -0
- investing_algorithm_framework/cli/templates/aws_lambda_readme.md.template +110 -0
- investing_algorithm_framework/cli/templates/aws_lambda_requirements.txt.template +2 -0
- investing_algorithm_framework/cli/templates/azure_function_function_app.py.template +65 -0
- investing_algorithm_framework/cli/templates/azure_function_host.json.template +15 -0
- investing_algorithm_framework/cli/templates/azure_function_local.settings.json.template +8 -0
- investing_algorithm_framework/cli/templates/azure_function_requirements.txt.template +3 -0
- investing_algorithm_framework/cli/templates/data_providers.py.template +17 -0
- investing_algorithm_framework/cli/templates/env.example.template +2 -0
- investing_algorithm_framework/cli/templates/env_azure_function.example.template +4 -0
- investing_algorithm_framework/cli/templates/market_data_providers.py.template +9 -0
- investing_algorithm_framework/cli/templates/readme.md.template +135 -0
- investing_algorithm_framework/cli/templates/requirements.txt.template +2 -0
- investing_algorithm_framework/cli/templates/run_backtest.py.template +20 -0
- investing_algorithm_framework/cli/templates/strategy.py.template +124 -0
- investing_algorithm_framework/cli/validate_backtest_checkpoints.py +197 -0
- investing_algorithm_framework/create_app.py +40 -7
- investing_algorithm_framework/dependency_container.py +100 -47
- investing_algorithm_framework/domain/__init__.py +97 -30
- investing_algorithm_framework/domain/algorithm_id.py +69 -0
- investing_algorithm_framework/domain/backtesting/__init__.py +25 -0
- investing_algorithm_framework/domain/backtesting/backtest.py +548 -0
- investing_algorithm_framework/domain/backtesting/backtest_date_range.py +113 -0
- investing_algorithm_framework/domain/backtesting/backtest_evaluation_focuss.py +241 -0
- investing_algorithm_framework/domain/backtesting/backtest_metrics.py +470 -0
- investing_algorithm_framework/domain/backtesting/backtest_permutation_test.py +275 -0
- investing_algorithm_framework/domain/backtesting/backtest_run.py +663 -0
- investing_algorithm_framework/domain/backtesting/backtest_summary_metrics.py +162 -0
- investing_algorithm_framework/domain/backtesting/backtest_utils.py +198 -0
- investing_algorithm_framework/domain/backtesting/combine_backtests.py +392 -0
- investing_algorithm_framework/domain/config.py +59 -136
- investing_algorithm_framework/domain/constants.py +18 -37
- investing_algorithm_framework/domain/data_provider.py +334 -0
- investing_algorithm_framework/domain/data_structures.py +42 -0
- investing_algorithm_framework/domain/exceptions.py +51 -1
- investing_algorithm_framework/domain/models/__init__.py +26 -19
- investing_algorithm_framework/domain/models/app_mode.py +34 -0
- investing_algorithm_framework/domain/models/data/__init__.py +7 -0
- investing_algorithm_framework/domain/models/data/data_source.py +222 -0
- investing_algorithm_framework/domain/models/data/data_type.py +46 -0
- investing_algorithm_framework/domain/models/event.py +35 -0
- investing_algorithm_framework/domain/models/market/__init__.py +5 -0
- investing_algorithm_framework/domain/models/market/market_credential.py +88 -0
- investing_algorithm_framework/domain/models/order/__init__.py +3 -4
- investing_algorithm_framework/domain/models/order/order.py +198 -65
- investing_algorithm_framework/domain/models/order/order_status.py +2 -2
- investing_algorithm_framework/domain/models/order/order_type.py +1 -3
- investing_algorithm_framework/domain/models/portfolio/__init__.py +6 -2
- investing_algorithm_framework/domain/models/portfolio/portfolio.py +98 -3
- investing_algorithm_framework/domain/models/portfolio/portfolio_configuration.py +37 -43
- investing_algorithm_framework/domain/models/portfolio/portfolio_snapshot.py +108 -11
- investing_algorithm_framework/domain/models/position/__init__.py +2 -1
- investing_algorithm_framework/domain/models/position/position.py +20 -0
- investing_algorithm_framework/domain/models/position/position_size.py +41 -0
- investing_algorithm_framework/domain/models/position/position_snapshot.py +0 -2
- investing_algorithm_framework/domain/models/risk_rules/__init__.py +7 -0
- investing_algorithm_framework/domain/models/risk_rules/stop_loss_rule.py +51 -0
- investing_algorithm_framework/domain/models/risk_rules/take_profit_rule.py +55 -0
- investing_algorithm_framework/domain/models/snapshot_interval.py +45 -0
- investing_algorithm_framework/domain/models/strategy_profile.py +19 -141
- investing_algorithm_framework/domain/models/time_frame.py +94 -98
- investing_algorithm_framework/domain/models/time_interval.py +33 -0
- investing_algorithm_framework/domain/models/time_unit.py +66 -2
- investing_algorithm_framework/domain/models/tracing/__init__.py +0 -0
- investing_algorithm_framework/domain/models/tracing/trace.py +23 -0
- investing_algorithm_framework/domain/models/trade/__init__.py +11 -0
- investing_algorithm_framework/domain/models/trade/trade.py +389 -0
- investing_algorithm_framework/domain/models/trade/trade_status.py +40 -0
- investing_algorithm_framework/domain/models/trade/trade_stop_loss.py +332 -0
- investing_algorithm_framework/domain/models/trade/trade_take_profit.py +365 -0
- investing_algorithm_framework/domain/order_executor.py +112 -0
- investing_algorithm_framework/domain/portfolio_provider.py +118 -0
- investing_algorithm_framework/domain/services/__init__.py +11 -0
- investing_algorithm_framework/domain/services/market_credential_service.py +37 -0
- investing_algorithm_framework/domain/services/portfolios/__init__.py +5 -0
- investing_algorithm_framework/domain/services/portfolios/portfolio_sync_service.py +9 -0
- investing_algorithm_framework/domain/services/rounding_service.py +27 -0
- investing_algorithm_framework/domain/services/state_handler.py +38 -0
- investing_algorithm_framework/domain/strategy.py +1 -29
- investing_algorithm_framework/domain/utils/__init__.py +15 -5
- investing_algorithm_framework/domain/utils/csv.py +22 -0
- investing_algorithm_framework/domain/utils/custom_tqdm.py +22 -0
- investing_algorithm_framework/domain/utils/dates.py +57 -0
- investing_algorithm_framework/domain/utils/jupyter_notebook_detection.py +19 -0
- investing_algorithm_framework/domain/utils/polars.py +53 -0
- investing_algorithm_framework/domain/utils/random.py +29 -0
- investing_algorithm_framework/download_data.py +244 -0
- investing_algorithm_framework/infrastructure/__init__.py +37 -11
- investing_algorithm_framework/infrastructure/data_providers/__init__.py +36 -0
- investing_algorithm_framework/infrastructure/data_providers/ccxt.py +1152 -0
- investing_algorithm_framework/infrastructure/data_providers/csv.py +568 -0
- investing_algorithm_framework/infrastructure/data_providers/pandas.py +599 -0
- investing_algorithm_framework/infrastructure/database/__init__.py +6 -2
- investing_algorithm_framework/infrastructure/database/sql_alchemy.py +86 -12
- investing_algorithm_framework/infrastructure/models/__init__.py +7 -3
- investing_algorithm_framework/infrastructure/models/order/__init__.py +2 -2
- investing_algorithm_framework/infrastructure/models/order/order.py +53 -53
- investing_algorithm_framework/infrastructure/models/order/order_metadata.py +44 -0
- investing_algorithm_framework/infrastructure/models/order_trade_association.py +10 -0
- investing_algorithm_framework/infrastructure/models/portfolio/__init__.py +1 -1
- investing_algorithm_framework/infrastructure/models/portfolio/portfolio_snapshot.py +8 -2
- investing_algorithm_framework/infrastructure/models/portfolio/{portfolio.py → sql_portfolio.py} +17 -6
- investing_algorithm_framework/infrastructure/models/position/position_snapshot.py +3 -1
- investing_algorithm_framework/infrastructure/models/trades/__init__.py +9 -0
- investing_algorithm_framework/infrastructure/models/trades/trade.py +130 -0
- investing_algorithm_framework/infrastructure/models/trades/trade_stop_loss.py +59 -0
- investing_algorithm_framework/infrastructure/models/trades/trade_take_profit.py +55 -0
- investing_algorithm_framework/infrastructure/order_executors/__init__.py +21 -0
- investing_algorithm_framework/infrastructure/order_executors/backtest_oder_executor.py +28 -0
- investing_algorithm_framework/infrastructure/order_executors/ccxt_order_executor.py +200 -0
- investing_algorithm_framework/infrastructure/portfolio_providers/__init__.py +19 -0
- investing_algorithm_framework/infrastructure/portfolio_providers/ccxt_portfolio_provider.py +199 -0
- investing_algorithm_framework/infrastructure/repositories/__init__.py +10 -4
- investing_algorithm_framework/infrastructure/repositories/order_metadata_repository.py +17 -0
- investing_algorithm_framework/infrastructure/repositories/order_repository.py +16 -5
- investing_algorithm_framework/infrastructure/repositories/portfolio_repository.py +2 -2
- investing_algorithm_framework/infrastructure/repositories/position_repository.py +11 -0
- investing_algorithm_framework/infrastructure/repositories/repository.py +84 -30
- investing_algorithm_framework/infrastructure/repositories/trade_repository.py +71 -0
- investing_algorithm_framework/infrastructure/repositories/trade_stop_loss_repository.py +29 -0
- investing_algorithm_framework/infrastructure/repositories/trade_take_profit_repository.py +29 -0
- investing_algorithm_framework/infrastructure/services/__init__.py +9 -4
- investing_algorithm_framework/infrastructure/services/aws/__init__.py +6 -0
- investing_algorithm_framework/infrastructure/services/aws/state_handler.py +193 -0
- investing_algorithm_framework/infrastructure/services/azure/__init__.py +5 -0
- investing_algorithm_framework/infrastructure/services/azure/state_handler.py +158 -0
- investing_algorithm_framework/infrastructure/services/backtesting/__init__.py +9 -0
- investing_algorithm_framework/infrastructure/services/backtesting/backtest_service.py +2596 -0
- investing_algorithm_framework/infrastructure/services/backtesting/event_backtest_service.py +285 -0
- investing_algorithm_framework/infrastructure/services/backtesting/vector_backtest_service.py +468 -0
- investing_algorithm_framework/services/__init__.py +123 -15
- investing_algorithm_framework/services/configuration_service.py +77 -11
- investing_algorithm_framework/services/data_providers/__init__.py +5 -0
- investing_algorithm_framework/services/data_providers/data_provider_service.py +1058 -0
- investing_algorithm_framework/services/market_credential_service.py +40 -0
- investing_algorithm_framework/services/metrics/__init__.py +119 -0
- investing_algorithm_framework/services/metrics/alpha.py +0 -0
- investing_algorithm_framework/services/metrics/beta.py +0 -0
- investing_algorithm_framework/services/metrics/cagr.py +60 -0
- investing_algorithm_framework/services/metrics/calmar_ratio.py +40 -0
- investing_algorithm_framework/services/metrics/drawdown.py +218 -0
- investing_algorithm_framework/services/metrics/equity_curve.py +24 -0
- investing_algorithm_framework/services/metrics/exposure.py +210 -0
- investing_algorithm_framework/services/metrics/generate.py +358 -0
- investing_algorithm_framework/services/metrics/mean_daily_return.py +84 -0
- investing_algorithm_framework/services/metrics/price_efficiency.py +57 -0
- investing_algorithm_framework/services/metrics/profit_factor.py +165 -0
- investing_algorithm_framework/services/metrics/recovery.py +113 -0
- investing_algorithm_framework/services/metrics/returns.py +452 -0
- investing_algorithm_framework/services/metrics/risk_free_rate.py +28 -0
- investing_algorithm_framework/services/metrics/sharpe_ratio.py +137 -0
- investing_algorithm_framework/services/metrics/sortino_ratio.py +74 -0
- investing_algorithm_framework/services/metrics/standard_deviation.py +156 -0
- investing_algorithm_framework/services/metrics/trades.py +473 -0
- investing_algorithm_framework/services/metrics/treynor_ratio.py +0 -0
- investing_algorithm_framework/services/metrics/ulcer.py +0 -0
- investing_algorithm_framework/services/metrics/value_at_risk.py +0 -0
- investing_algorithm_framework/services/metrics/volatility.py +118 -0
- investing_algorithm_framework/services/metrics/win_rate.py +177 -0
- investing_algorithm_framework/services/order_service/__init__.py +9 -0
- investing_algorithm_framework/services/order_service/order_backtest_service.py +178 -0
- investing_algorithm_framework/services/order_service/order_executor_lookup.py +110 -0
- investing_algorithm_framework/services/order_service/order_service.py +826 -0
- investing_algorithm_framework/services/portfolios/__init__.py +16 -0
- investing_algorithm_framework/services/portfolios/backtest_portfolio_service.py +54 -0
- investing_algorithm_framework/services/{portfolio_configuration_service.py → portfolios/portfolio_configuration_service.py} +27 -12
- investing_algorithm_framework/services/portfolios/portfolio_provider_lookup.py +106 -0
- investing_algorithm_framework/services/portfolios/portfolio_service.py +188 -0
- investing_algorithm_framework/services/portfolios/portfolio_snapshot_service.py +136 -0
- investing_algorithm_framework/services/portfolios/portfolio_sync_service.py +182 -0
- investing_algorithm_framework/services/positions/__init__.py +7 -0
- investing_algorithm_framework/services/positions/position_service.py +210 -0
- investing_algorithm_framework/services/repository_service.py +8 -2
- investing_algorithm_framework/services/trade_order_evaluator/__init__.py +9 -0
- investing_algorithm_framework/services/trade_order_evaluator/backtest_trade_oder_evaluator.py +117 -0
- investing_algorithm_framework/services/trade_order_evaluator/default_trade_order_evaluator.py +51 -0
- investing_algorithm_framework/services/trade_order_evaluator/trade_order_evaluator.py +80 -0
- investing_algorithm_framework/services/trade_service/__init__.py +9 -0
- investing_algorithm_framework/services/trade_service/trade_service.py +1099 -0
- investing_algorithm_framework/services/trade_service/trade_stop_loss_service.py +39 -0
- investing_algorithm_framework/services/trade_service/trade_take_profit_service.py +41 -0
- investing_algorithm_framework-7.25.6.dist-info/METADATA +535 -0
- investing_algorithm_framework-7.25.6.dist-info/RECORD +268 -0
- {investing_algorithm_framework-1.5.dist-info → investing_algorithm_framework-7.25.6.dist-info}/WHEEL +1 -2
- investing_algorithm_framework-7.25.6.dist-info/entry_points.txt +3 -0
- investing_algorithm_framework/app/algorithm.py +0 -630
- investing_algorithm_framework/domain/models/backtest_profile.py +0 -414
- investing_algorithm_framework/domain/models/market_data/__init__.py +0 -11
- investing_algorithm_framework/domain/models/market_data/asset_price.py +0 -50
- investing_algorithm_framework/domain/models/market_data/ohlcv.py +0 -105
- investing_algorithm_framework/domain/models/market_data/order_book.py +0 -63
- investing_algorithm_framework/domain/models/market_data/ticker.py +0 -92
- investing_algorithm_framework/domain/models/order/order_fee.py +0 -45
- investing_algorithm_framework/domain/models/trade.py +0 -78
- investing_algorithm_framework/domain/models/trading_data_types.py +0 -47
- investing_algorithm_framework/domain/models/trading_time_frame.py +0 -223
- investing_algorithm_framework/domain/singleton.py +0 -9
- investing_algorithm_framework/domain/utils/backtesting.py +0 -82
- investing_algorithm_framework/infrastructure/models/order/order_fee.py +0 -21
- investing_algorithm_framework/infrastructure/repositories/order_fee_repository.py +0 -15
- investing_algorithm_framework/infrastructure/services/market_backtest_service.py +0 -360
- investing_algorithm_framework/infrastructure/services/market_service.py +0 -410
- investing_algorithm_framework/infrastructure/services/performance_service.py +0 -192
- investing_algorithm_framework/services/backtest_service.py +0 -268
- investing_algorithm_framework/services/market_data_service.py +0 -77
- investing_algorithm_framework/services/order_backtest_service.py +0 -122
- investing_algorithm_framework/services/order_service.py +0 -752
- investing_algorithm_framework/services/portfolio_service.py +0 -164
- investing_algorithm_framework/services/portfolio_snapshot_service.py +0 -68
- investing_algorithm_framework/services/position_cost_service.py +0 -5
- investing_algorithm_framework/services/position_service.py +0 -63
- investing_algorithm_framework/services/strategy_orchestrator_service.py +0 -225
- investing_algorithm_framework-1.5.dist-info/AUTHORS.md +0 -8
- investing_algorithm_framework-1.5.dist-info/METADATA +0 -230
- investing_algorithm_framework-1.5.dist-info/RECORD +0 -119
- investing_algorithm_framework-1.5.dist-info/top_level.txt +0 -1
- /investing_algorithm_framework/{infrastructure/services/performance_backtest_service.py → app/reporting/tables/stop_loss_table.py} +0 -0
- /investing_algorithm_framework/services/{position_snapshot_service.py → positions/position_snapshot_service.py} +0 -0
- {investing_algorithm_framework-1.5.dist-info → investing_algorithm_framework-7.25.6.dist-info}/LICENSE +0 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# README created by investing_algorithm_framework
|
|
2
|
+
|
|
3
|
+
You can find the documentation for the investing_algorithm_framework
|
|
4
|
+
[here](https://coding-kitties.github.io/investing-algorithm-framework).
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## Getting Started
|
|
8
|
+
|
|
9
|
+
This project was created using the investing_algorithm_framework CLI. It provides a template for building a trading algorithm using the investing_algorithm_framework.
|
|
10
|
+
|
|
11
|
+
This repository contains a simple trading algorithm that uses the
|
|
12
|
+
`investing_algorithm_framework` to fetch data from [bitvavo](https://www.bitvavo.com/en/) and execute trades on the [bitvavo exchange](https://www.bitvavo.com/en/).
|
|
13
|
+
|
|
14
|
+
The trading strategy is a simple moving average crossover strategy that uses the 50 and 100 day moving averages and the 200 day moving average as a trend filter. The strategy is implemented in the `strategy.py` file. The data provider is implemented in the `data_providers.py` file.
|
|
15
|
+
|
|
16
|
+
All indicators are implemented with the [pyindicators](https://github.com/coding-kitties/PyIndicators) library.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
#### 1. Install the requirements
|
|
20
|
+
|
|
21
|
+
You can install the requirements using the following command:
|
|
22
|
+
```bash
|
|
23
|
+
pip install -r requirements.txt
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
This will install the `investing_algorithm_framework`, `pyindicators`, and
|
|
27
|
+
`python-dotenv` libraries. If you use the azure functions type option, it will also install the `azure-functions` library.
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
#### 2. Create a `.env` file
|
|
31
|
+
You need to create a `.env` file in the root of the project. You can use the `.env.example` file as a template. The `.env` file should contain the following environment variables:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
BITVAVO_API_KEY=your_api_key
|
|
35
|
+
BITVAVO_API_SECRET=your_api_secret
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
##### 2.1 Changing the exchange
|
|
39
|
+
You can change the exchange in the `app.py` file. The default is set to `bitvavo`, but you can change it to any exchange you want. You can find the list of supported exchanges [here](https://investing-algorithm-framework.com/Getting%20Started/markets).
|
|
40
|
+
|
|
41
|
+
##### 2.2 Azure Functions `.env` file
|
|
42
|
+
If you are using the azure functions type option, you also need to add the following environment variables:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
AZURE_STORAGE_CONNECTION_STRING=your_azure_storage_connection_string
|
|
46
|
+
AZURE_STORAGE_CONTAINER_NAME=your_azure_storage_container_name
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
If you would like to have guidance on how to create the azure storage connection string, you can find it [here](https://learn.microsoft.com/en-us/azure/storage/common/storage-account-create?tabs=azure-portal).
|
|
50
|
+
|
|
51
|
+
#### 3. Run the app (Skip this step if you have not backtested your strategy)
|
|
52
|
+
> This will run the app as if it was run in production. It will execute live
|
|
53
|
+
> trades on your connected exchange. Please only run this if you are
|
|
54
|
+
> comfortable with this and have backtested your strategy.
|
|
55
|
+
|
|
56
|
+
You can run the app using the following command:
|
|
57
|
+
```bash
|
|
58
|
+
python app.py
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
This will start the app and run the trading algorithm. The app will fetch data from the bitvavo exchange and execute trades based on the trading strategy.
|
|
62
|
+
|
|
63
|
+
#### 3.1 Run the app with azure functions locally
|
|
64
|
+
> Make sure to have the azure functions core tools installed. You can find the
|
|
65
|
+
> installation instructions [here](https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local).
|
|
66
|
+
|
|
67
|
+
If you are using the azure functions type option, you can run the app locally using the following command:
|
|
68
|
+
```bash
|
|
69
|
+
func start
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
#### 4. Run the backtest
|
|
73
|
+
You can run the backtest using the following command:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
python run_backtest.py
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
#### 5. Deployment
|
|
80
|
+
You can deploy your trading bot in varous ways.
|
|
81
|
+
|
|
82
|
+
##### 5.1 Azure Functions
|
|
83
|
+
You can deploy your trading bot to azure functions using the following command:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
investing-algorithm-framework deploy --type function --cloud azure
|
|
87
|
+
```
|
|
88
|
+
This will deploy your trading bot to azure functions. You can find the deployment instructions [here](https://investing-algorithm-framework.com/Getting%20Started/deployment).
|
|
89
|
+
|
|
90
|
+
## Project Structure
|
|
91
|
+
|
|
92
|
+
> We highly recommend to keep the file structure as is, as it is
|
|
93
|
+
> designed to work with the investing_algorithm_framework CLI.
|
|
94
|
+
> You can add your own files and folders as needed, however, we
|
|
95
|
+
> recommend to keep the `strategies` folder for your strategies
|
|
96
|
+
> and the `app.py` file for your app entry point.
|
|
97
|
+
|
|
98
|
+
```yaml
|
|
99
|
+
.
|
|
100
|
+
├── app.py
|
|
101
|
+
├── requirements.txt
|
|
102
|
+
├── strategies
|
|
103
|
+
│ ├── data_providers.py
|
|
104
|
+
│ └── strategy.py
|
|
105
|
+
├── .gitignore
|
|
106
|
+
├── .env.example
|
|
107
|
+
└── README.md
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
If you're using the azure functions type option, you will also have an `function_app.py`, `local.settings.json`, and `function.json` file. The `function_app.py` file is the entry point for the azure function, and the `local.settings.json` file is used to configure the local environment for the azure function. The `function.json` file is used to configure the function itself.
|
|
111
|
+
|
|
112
|
+
> You can change the time trigger in the `function_app.py` when
|
|
113
|
+
> using the azure functions type option. The default is set to
|
|
114
|
+
> every 30 seconds. You can change it to any time you want,
|
|
115
|
+
> but make sure to use the correct format for the time trigger.
|
|
116
|
+
|
|
117
|
+
## Requirements
|
|
118
|
+
|
|
119
|
+
The project requires Python 3.10 or higher. You can create a virtual environment and install the requirements using the following commands:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
virtualenv venv
|
|
123
|
+
source venv/bin/activate # On Windows use `venv\Scripts\activate`
|
|
124
|
+
pip install -r requirements.txt
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
By default pyindicators is installed as its specified in the requirements.txt file. This is a requirement for the example strategy in the `strategy.py` file. You can always remove it from the requirements.txt file if you don't need it.
|
|
128
|
+
|
|
129
|
+
## Deployment
|
|
130
|
+
|
|
131
|
+
You can deploy your trading bot to azure functions using the following cli command:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
investing-algorithm-framework deploy --type function --cloud azure
|
|
135
|
+
```
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
from investing_algorithm_framework import BacktestDateRange
|
|
4
|
+
from investing_algorithm_framework import create_app
|
|
5
|
+
from strategies.strategy import MyTradingStrategy
|
|
6
|
+
|
|
7
|
+
app = create_app()
|
|
8
|
+
app.add_strategy(MyTradingStrategy)
|
|
9
|
+
app.add_market(market="BITVAVO", trading_symbol="EUR")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
if __name__ == "__main__":
|
|
13
|
+
backtest_date_range = BacktestDateRange(
|
|
14
|
+
start_date=datetime(2023, 1, 1),
|
|
15
|
+
end_date=datetime(2023, 12, 31),
|
|
16
|
+
)
|
|
17
|
+
report = app.run_backtest(
|
|
18
|
+
backtest_date_range=backtest_date_range, initial_amount=1000
|
|
19
|
+
)
|
|
20
|
+
report.show()
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
from investing_algorithm_framework import TimeUnit, TradingStrategy, Context, \
|
|
2
|
+
OrderSide
|
|
3
|
+
from .data_providers import btc_eur_ohlcv_2h, btc_eur_ticker
|
|
4
|
+
from pyindicators import ema, is_crossover, is_above, is_below, is_crossunder
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MyTradingStrategy(TradingStrategy):
|
|
8
|
+
"""
|
|
9
|
+
A simple trading strategy that uses EMA crossovers to generate buy and
|
|
10
|
+
sell signals. The strategy uses a 50-period EMA and a 100-period EMA
|
|
11
|
+
to detect golden and death crosses. It also uses a 200-period EMA to
|
|
12
|
+
determine the overall trend direction. The strategy trades BTC/EUR
|
|
13
|
+
on a 2-hour timeframe. The strategy is designed to be used with the
|
|
14
|
+
Investing Algorithm Framework and uses the PyIndicators library
|
|
15
|
+
to calculate the EMAs and crossover signals.
|
|
16
|
+
|
|
17
|
+
The strategy uses a trailing stop loss and take profit to manage
|
|
18
|
+
risk. The stop loss is set to 5% below the entry price and the
|
|
19
|
+
take profit is set to 10% above the entry price. The stop loss and
|
|
20
|
+
take profit are both trailing, meaning that they will move up
|
|
21
|
+
with the price when the price goes up.
|
|
22
|
+
"""
|
|
23
|
+
time_unit = TimeUnit.HOUR
|
|
24
|
+
interval = 2
|
|
25
|
+
symbol_pairs = ["BTC/EUR"]
|
|
26
|
+
market_data_sources = [btc_eur_ohlcv_2h, btc_eur_ticker]
|
|
27
|
+
fast = 50
|
|
28
|
+
slow = 100
|
|
29
|
+
trend = 200
|
|
30
|
+
stop_loss_percentage = 2
|
|
31
|
+
stop_loss_sell_size = 50
|
|
32
|
+
take_profit_percentage = 8
|
|
33
|
+
take_profit_sell_size = 50
|
|
34
|
+
|
|
35
|
+
def apply_strategy(self, context: Context, market_data):
|
|
36
|
+
|
|
37
|
+
for pair in self.symbol_pairs:
|
|
38
|
+
symbol = pair.split('/')[0]
|
|
39
|
+
|
|
40
|
+
# Don't trade if there are open orders for the symbol
|
|
41
|
+
# This is important to avoid placing new orders while there are
|
|
42
|
+
# existing orders that are not yet filled
|
|
43
|
+
if context.has_open_orders(symbol):
|
|
44
|
+
continue
|
|
45
|
+
|
|
46
|
+
ohlvc_data = market_data[f"{pair}-ohlcv-2h"]
|
|
47
|
+
# ticker_data = market_data[f"{symbol}-ticker"]
|
|
48
|
+
# Add fast, slow, and trend EMAs to the data
|
|
49
|
+
ohlvc_data = ema(
|
|
50
|
+
ohlvc_data,
|
|
51
|
+
source_column="Close",
|
|
52
|
+
period=self.fast,
|
|
53
|
+
result_column=f"ema_{self.fast}"
|
|
54
|
+
)
|
|
55
|
+
ohlvc_data = ema(
|
|
56
|
+
ohlvc_data,
|
|
57
|
+
source_column="Close",
|
|
58
|
+
period=self.slow,
|
|
59
|
+
result_column=f"ema_{self.slow}"
|
|
60
|
+
)
|
|
61
|
+
ohlvc_data = ema(
|
|
62
|
+
ohlvc_data,
|
|
63
|
+
source_column="Close",
|
|
64
|
+
period=self.trend,
|
|
65
|
+
result_column=f"ema_{self.trend}"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
price = ohlvc_data["Close"][-1]
|
|
69
|
+
|
|
70
|
+
if not context.has_position(symbol) \
|
|
71
|
+
and self._is_buy_signal(ohlvc_data):
|
|
72
|
+
order = context.create_limit_order(
|
|
73
|
+
target_symbol=symbol,
|
|
74
|
+
order_side=OrderSide.BUY,
|
|
75
|
+
price=price,
|
|
76
|
+
percentage_of_portfolio=25,
|
|
77
|
+
precision=4,
|
|
78
|
+
)
|
|
79
|
+
trade = context.get_trade(order_id=order.id)
|
|
80
|
+
context.add_stop_loss(
|
|
81
|
+
trade=trade,
|
|
82
|
+
trade_risk_type="trailing",
|
|
83
|
+
percentage=self.stop_loss_percentage,
|
|
84
|
+
sell_percentage=self.stop_loss_sell_size
|
|
85
|
+
)
|
|
86
|
+
context.add_take_profit(
|
|
87
|
+
trade=trade,
|
|
88
|
+
percentage=self.take_profit_percentage,
|
|
89
|
+
trade_risk_type="trailing",
|
|
90
|
+
sell_percentage=self.take_profit_sell_size
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
if context.has_position(symbol) \
|
|
94
|
+
and self._is_sell_signal(ohlvc_data):
|
|
95
|
+
open_trades = context.get_open_trades(
|
|
96
|
+
target_symbol=symbol
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
for trade in open_trades:
|
|
100
|
+
context.close_trade(trade)
|
|
101
|
+
|
|
102
|
+
def _is_sell_signal(self, data):
|
|
103
|
+
return is_crossunder(
|
|
104
|
+
data,
|
|
105
|
+
first_column=f"ema_{self.fast}",
|
|
106
|
+
second_column=f"ema_{self.slow}",
|
|
107
|
+
number_of_data_points=2
|
|
108
|
+
) and is_below(
|
|
109
|
+
data,
|
|
110
|
+
first_column=f"ema_{self.fast}",
|
|
111
|
+
second_column=f"ema_{self.trend}",
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
def _is_buy_signal(self, data):
|
|
115
|
+
return is_crossover(
|
|
116
|
+
data=data,
|
|
117
|
+
first_column=f"ema_{self.fast}",
|
|
118
|
+
second_column=f"ema_{self.slow}",
|
|
119
|
+
number_of_data_points=2
|
|
120
|
+
) and is_above(
|
|
121
|
+
data=data,
|
|
122
|
+
first_column=f"ema_{self.fast}",
|
|
123
|
+
second_column=f"ema_{self.trend}",
|
|
124
|
+
)
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CLI command to validate backtest checkpoints from a directory.
|
|
3
|
+
|
|
4
|
+
This command scans a directory for backtest results and creates or updates
|
|
5
|
+
a checkpoints.json file with all found backtests organized by date ranges.
|
|
6
|
+
"""
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
from typing import Dict, List
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
|
|
13
|
+
from investing_algorithm_framework.domain import Backtest
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def validate_and_create_checkpoints(
|
|
17
|
+
directory_path: str,
|
|
18
|
+
output_file: str = None,
|
|
19
|
+
verbose: bool = False
|
|
20
|
+
) -> Dict[str, List[str]]:
|
|
21
|
+
"""
|
|
22
|
+
Validate a directory for backtest checkpoints and create a checkpoint file.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
directory_path (str): Path to the directory containing
|
|
26
|
+
backtest results.
|
|
27
|
+
output_file (str, optional): Custom path for the output
|
|
28
|
+
checkpoint file. If None, will create 'checkpoints.json'
|
|
29
|
+
in the directory_path.
|
|
30
|
+
verbose (bool): Whether to print detailed information.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Dict[str, List[str]]: Dictionary mapping date range
|
|
34
|
+
keys to algorithm IDs.
|
|
35
|
+
"""
|
|
36
|
+
if not os.path.exists(directory_path):
|
|
37
|
+
raise click.ClickException(
|
|
38
|
+
f"Directory {directory_path} does not exist."
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Determine output file path
|
|
42
|
+
if output_file is None:
|
|
43
|
+
output_file = os.path.join(directory_path, "checkpoints.json")
|
|
44
|
+
|
|
45
|
+
checkpoints = {}
|
|
46
|
+
valid_backtests = 0
|
|
47
|
+
invalid_dirs = 0
|
|
48
|
+
|
|
49
|
+
if verbose:
|
|
50
|
+
click.echo(f"Scanning directory: {directory_path}")
|
|
51
|
+
click.echo("-" * 60)
|
|
52
|
+
|
|
53
|
+
# Scan all subdirectories in the target directory
|
|
54
|
+
for item in os.listdir(directory_path):
|
|
55
|
+
item_path = os.path.join(directory_path, item)
|
|
56
|
+
|
|
57
|
+
# Skip files, only process directories
|
|
58
|
+
if not os.path.isdir(item_path):
|
|
59
|
+
continue
|
|
60
|
+
|
|
61
|
+
# Skip the checkpoints.json file itself
|
|
62
|
+
if item == "checkpoints.json":
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
try:
|
|
66
|
+
# Try to load the backtest
|
|
67
|
+
backtest = Backtest.open(item_path)
|
|
68
|
+
|
|
69
|
+
if backtest.algorithm_id is None:
|
|
70
|
+
if verbose:
|
|
71
|
+
click.echo(
|
|
72
|
+
f"⚠️ Warning: {item} - No "
|
|
73
|
+
f"algorithm_id found, skipping"
|
|
74
|
+
)
|
|
75
|
+
invalid_dirs += 1
|
|
76
|
+
continue
|
|
77
|
+
|
|
78
|
+
# Process each backtest run to extract date ranges
|
|
79
|
+
if backtest.backtest_runs:
|
|
80
|
+
for run in backtest.get_all_backtest_runs():
|
|
81
|
+
# Create date range key in the format used by the framework
|
|
82
|
+
start_date = run.backtest_start_date.isoformat()
|
|
83
|
+
end_date = run.backtest_end_date.isoformat()
|
|
84
|
+
date_range_key = f"{start_date}_{end_date}"
|
|
85
|
+
|
|
86
|
+
# Add algorithm_id to the checkpoint for this date range
|
|
87
|
+
if date_range_key not in checkpoints:
|
|
88
|
+
checkpoints[date_range_key] = []
|
|
89
|
+
|
|
90
|
+
if backtest.algorithm_id \
|
|
91
|
+
not in checkpoints[date_range_key]:
|
|
92
|
+
checkpoints[date_range_key].append(
|
|
93
|
+
backtest.algorithm_id
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
if verbose:
|
|
97
|
+
click.echo(
|
|
98
|
+
f"✓ {item} - Algorithm: "
|
|
99
|
+
f"{backtest.algorithm_id}, "
|
|
100
|
+
f"Range: {start_date} to {end_date}"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
valid_backtests += 1
|
|
104
|
+
else:
|
|
105
|
+
if verbose:
|
|
106
|
+
click.echo(
|
|
107
|
+
f"⚠️ Warning: {item} - No backtest runs found"
|
|
108
|
+
)
|
|
109
|
+
invalid_dirs += 1
|
|
110
|
+
|
|
111
|
+
except Exception as e:
|
|
112
|
+
if verbose:
|
|
113
|
+
click.echo(f"✗ {item} - Not a valid backtest: {str(e)}")
|
|
114
|
+
invalid_dirs += 1
|
|
115
|
+
continue
|
|
116
|
+
|
|
117
|
+
# Sort algorithm IDs in each checkpoint for consistency
|
|
118
|
+
for date_range_key in checkpoints:
|
|
119
|
+
checkpoints[date_range_key].sort()
|
|
120
|
+
|
|
121
|
+
# Write checkpoint file
|
|
122
|
+
with open(output_file, 'w') as f:
|
|
123
|
+
json.dump(checkpoints, f, indent=4)
|
|
124
|
+
|
|
125
|
+
# Print summary
|
|
126
|
+
if verbose:
|
|
127
|
+
click.echo("-" * 60)
|
|
128
|
+
|
|
129
|
+
click.echo("\n✓ Checkpoint validation complete!")
|
|
130
|
+
click.echo(f" Valid backtests found: {valid_backtests}")
|
|
131
|
+
click.echo(f" Invalid/skipped directories: {invalid_dirs}")
|
|
132
|
+
click.echo(f" Total date ranges: {len(checkpoints)}")
|
|
133
|
+
click.echo(f" Checkpoint file saved to: {output_file}\n")
|
|
134
|
+
|
|
135
|
+
if verbose and checkpoints:
|
|
136
|
+
click.echo("Date ranges found:")
|
|
137
|
+
for date_range_key, algorithm_ids in sorted(checkpoints.items()):
|
|
138
|
+
click.echo(
|
|
139
|
+
f" {date_range_key}: {len(algorithm_ids)} algorithm(s)"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
return checkpoints
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@click.command()
|
|
146
|
+
@click.argument(
|
|
147
|
+
'directory',
|
|
148
|
+
type=click.Path(exists=True, file_okay=False, dir_okay=True),
|
|
149
|
+
required=True
|
|
150
|
+
)
|
|
151
|
+
@click.option(
|
|
152
|
+
'--output',
|
|
153
|
+
'-o',
|
|
154
|
+
type=click.Path(),
|
|
155
|
+
default=None,
|
|
156
|
+
help='Output path for the checkpoint file. '
|
|
157
|
+
'Defaults to checkpoints.json in the target directory.'
|
|
158
|
+
)
|
|
159
|
+
@click.option(
|
|
160
|
+
'--verbose',
|
|
161
|
+
'-v',
|
|
162
|
+
is_flag=True,
|
|
163
|
+
default=False,
|
|
164
|
+
help='Print detailed information about each backtest found.'
|
|
165
|
+
)
|
|
166
|
+
def command(directory, output, verbose):
|
|
167
|
+
"""
|
|
168
|
+
Validate a directory for backtest checkpoints and create/update
|
|
169
|
+
checkpoints.json.
|
|
170
|
+
|
|
171
|
+
This command scans DIRECTORY for backtest results, validates
|
|
172
|
+
each subdirectory to check if it contains a valid backtest, and
|
|
173
|
+
creates a checkpoints.json file mapping date ranges to algorithm IDs.
|
|
174
|
+
|
|
175
|
+
Example usage:
|
|
176
|
+
|
|
177
|
+
\b
|
|
178
|
+
# Validate backtests in a directory
|
|
179
|
+
iaf validate-checkpoints /path/to/backtest/results
|
|
180
|
+
|
|
181
|
+
\b
|
|
182
|
+
# With verbose output
|
|
183
|
+
iaf validate-checkpoints /path/to/backtest/results --verbose
|
|
184
|
+
|
|
185
|
+
\b
|
|
186
|
+
# Save to a custom location
|
|
187
|
+
iaf validate-checkpoints /path/to/backtest/results -o
|
|
188
|
+
/path/to/checkpoints.json
|
|
189
|
+
"""
|
|
190
|
+
try:
|
|
191
|
+
validate_and_create_checkpoints(
|
|
192
|
+
directory_path=directory,
|
|
193
|
+
output_file=output,
|
|
194
|
+
verbose=verbose
|
|
195
|
+
)
|
|
196
|
+
except Exception as e:
|
|
197
|
+
raise click.ClickException(f"Error validating checkpoints: {str(e)}")
|
|
@@ -1,21 +1,54 @@
|
|
|
1
|
+
import os
|
|
1
2
|
import logging
|
|
3
|
+
import inspect
|
|
4
|
+
from dotenv import load_dotenv
|
|
2
5
|
|
|
3
6
|
from .app import App
|
|
4
7
|
from .dependency_container import setup_dependency_container
|
|
8
|
+
from .domain import AppMode, APPLICATION_DIRECTORY, APP_MODE
|
|
5
9
|
|
|
6
10
|
logger = logging.getLogger("investing_algorithm_framework")
|
|
7
11
|
|
|
12
|
+
|
|
8
13
|
def create_app(
|
|
9
|
-
config=
|
|
10
|
-
|
|
11
|
-
web=False,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
config: dict = None,
|
|
15
|
+
state_handler=None,
|
|
16
|
+
web: bool = False,
|
|
17
|
+
name=None
|
|
18
|
+
) -> App:
|
|
19
|
+
"""
|
|
20
|
+
Factory method to create an app instance.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
config (dict): Configuration dictionary
|
|
24
|
+
web (bool): Whether to create a web app
|
|
25
|
+
state_handler (StateHandler): State handler for the app
|
|
26
|
+
name (str): Name of the app
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
App: App instance
|
|
30
|
+
"""
|
|
31
|
+
# Load the environment variables
|
|
32
|
+
load_dotenv()
|
|
33
|
+
|
|
34
|
+
app = App(state_handler=state_handler)
|
|
14
35
|
app = setup_dependency_container(
|
|
15
36
|
app,
|
|
16
37
|
["investing_algorithm_framework"],
|
|
17
38
|
["investing_algorithm_framework"]
|
|
18
39
|
)
|
|
19
|
-
app.
|
|
20
|
-
|
|
40
|
+
app.name = name
|
|
41
|
+
|
|
42
|
+
if config is not None:
|
|
43
|
+
app.set_config_with_dict(config)
|
|
44
|
+
|
|
45
|
+
if web:
|
|
46
|
+
app.set_config(APP_MODE, AppMode.WEB.value)
|
|
47
|
+
|
|
48
|
+
# Add the application directory to the config
|
|
49
|
+
caller_frame = inspect.stack()[1]
|
|
50
|
+
caller_path = os.path.abspath(caller_frame.filename)
|
|
51
|
+
app.set_config(APPLICATION_DIRECTORY, caller_path)
|
|
52
|
+
|
|
53
|
+
logger.info("Investing algorithm framework app created")
|
|
21
54
|
return app
|