Skip to content

Commit 67ec6e6

Browse files
committed
Fix sync orders on first load
1 parent f99ab29 commit 67ec6e6

File tree

23 files changed

+429
-892
lines changed

23 files changed

+429
-892
lines changed

README.md

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ from investing_algorithm_framework import create_app, PortfolioConfiguration, \
4040
RESOURCE_DIRECTORY, TimeUnit, CCXTOHLCVMarketDataSource, Algorithm, \
4141
CCXTTickerMarketDataSource, MarketCredential, SYMBOLS
4242

43-
# Define the symbols you want to trade for optimization, otherwise it will
44-
# check all available symbols on the market
43+
# Define the symbols you want to trade for optimization, otherwise the
44+
# algorithm will check if you have orders and balances on all available
45+
# symbols on the market
4546
symbols = ["BTC/EUR"]
4647

4748
# Define resource directory and the symbols you want to trade
@@ -100,16 +101,25 @@ def perform_strategy(algorithm: Algorithm, market_data: dict):
100101

101102
# Ticker data is passed as {"<identifier>": <ticker dict>}
102103
ticker_data = market_data["BTC-ticker"]
103-
order = algorithm.create_limit_order(
104+
unallocated_balance = algorithm.get_unallocated()
105+
positions = algorithm.get_positions()
106+
trades = algorithm.get_trades()
107+
open_trades = algorithm.get_open_trades()
108+
closed_trades = algorithm.get_closed_trades()
109+
110+
# Create a buy oder
111+
algorithm.create_limit_order(
104112
target_symbol="BTC/EUR",
105113
order_side="buy",
106114
amount=0.01,
107115
price=ticker_data["ask"],
108116
)
109-
positions = algorithm.get_positions()
110-
trades = algorithm.get_trades()
111-
open_trades = algorithm.get_open_trades()
112-
closed_trades = algorithm.get_closed_trades()
117+
118+
# Close a trade
119+
algorithm.close_trade(trades[0].id)
120+
121+
# Close a position
122+
algorithm.close_position(positions[0].get_symbol())
113123

114124
if __name__ == "__main__":
115125
app.run()

examples/backtest_experiment/algorithms/algorithm.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from investing_algorithm_framework import Algorithm, TradingStrategy, \
2-
TimeUnit, OrderSide
2+
TimeUnit, OrderSide, DATETIME_FORMAT
33
import tulipy as ti
4+
import polars as pl
5+
46

57
def is_below_trend(fast_series, slow_series):
68
return fast_series[-1] < slow_series[-1]
@@ -39,10 +41,11 @@ class Strategy(TradingStrategy):
3941
]
4042
symbols = ["BTC/EUR", "DOT/EUR"]
4143

42-
def __init__(self, fast, slow, trend):
44+
def __init__(self, fast, slow, trend, stop_loss_percentage=4):
4345
self.fast = fast
4446
self.slow = slow
4547
self.trend = trend
48+
self.stop_loss_percentage = stop_loss_percentage
4649
super().__init__()
4750

4851
def apply_strategy(self, algorithm: Algorithm, market_data):
@@ -81,17 +84,35 @@ def apply_strategy(self, algorithm: Algorithm, market_data):
8184
for trade in open_trades:
8285
algorithm.close_trade(trade)
8386

87+
# Checking manual stop losses
88+
open_trades = algorithm.get_open_trades(target_symbol)
89+
90+
for open_trade in open_trades:
91+
filtered_df = df.filter(
92+
pl.col('Datetime') >= open_trade.opened_at.strftime(DATETIME_FORMAT)
93+
)
94+
close_prices = filtered_df['Close'].to_numpy()
95+
current_price = market_data[f"{symbol}-ticker"]
96+
97+
if open_trade.is_manual_stop_loss_trigger(
98+
prices=close_prices,
99+
current_price=current_price["bid"],
100+
stop_loss_percentage=self.stop_loss_percentage
101+
):
102+
algorithm.close_trade(open_trade)
103+
84104

85105
def create_algorithm(
86106
name,
87107
description,
88108
fast,
89109
slow,
90-
trend
110+
trend,
111+
stop_loss_percentage
91112
) -> Algorithm:
92113
algorithm = Algorithm(
93114
name=name,
94115
description=description
95116
)
96-
algorithm.add_strategy(Strategy(fast, slow, trend))
117+
algorithm.add_strategy(Strategy(fast, slow, trend, stop_loss_percentage))
97118
return algorithm

examples/backtest_experiment/backtest.py

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,126 +25,144 @@
2525
description="9-50-100",
2626
fast=9,
2727
slow=50,
28-
trend=100
28+
trend=100,
29+
stop_loss_percentage=7
2930
),
3031
create_algorithm(
3132
name="10-50-100",
3233
description="10-50-100",
3334
fast=10,
3435
slow=50,
35-
trend=100
36+
trend=100,
37+
stop_loss_percentage=7
3638
),
3739
create_algorithm(
3840
name="11-50-100",
3941
description="11-50-100",
4042
fast=11,
4143
slow=50,
42-
trend=100
44+
trend=100,
45+
stop_loss_percentage=7
4346
),
4447
create_algorithm(
4548
name="9-75-150",
4649
description="9-75-150",
4750
fast=9,
4851
slow=75,
49-
trend=150
52+
trend=150,
53+
stop_loss_percentage=7
5054
),
5155
create_algorithm(
5256
name="10-75-150",
5357
description="10-75-150",
5458
fast=10,
5559
slow=75,
56-
trend=150
60+
trend=150,
61+
stop_loss_percentage=7
5762
),
5863
create_algorithm(
5964
name="11-75-150",
6065
description="11-75-150",
6166
fast=11,
6267
slow=75,
63-
trend=150
68+
trend=150,
69+
stop_loss_percentage=7
6470
),
6571
create_algorithm(
6672
name="20-75-150",
6773
description="20-75-150",
6874
fast=20,
6975
slow=75,
70-
trend=150
76+
trend=150,
77+
stop_loss_percentage=7
7178
),
7279
create_algorithm(
7380
name="21-75-150",
7481
description="21-75-150",
7582
fast=21,
7683
slow=75,
77-
trend=150
84+
trend=150,
85+
stop_loss_percentage=7
7886
),
7987
create_algorithm(
8088
name="22-75-150",
8189
description="22-75-150",
8290
fast=22,
8391
slow=75,
84-
trend=150
92+
trend=150,
93+
stop_loss_percentage=7
8594
),
8695
create_algorithm(
8796
name="23-75-150",
8897
description="23-75-150",
8998
fast=23,
9099
slow=75,
91-
trend=150
100+
trend=150,
101+
stop_loss_percentage=7
92102
),
93103
create_algorithm(
94104
name="24-75-150",
95105
description="24-75-150",
96106
fast=24,
97107
slow=75,
98-
trend=150
108+
trend=150,
109+
stop_loss_percentage=7
99110
),
100111
create_algorithm(
101112
name="25-75-150",
102113
description="25-75-150",
103114
fast=25,
104115
slow=75,
105-
trend=150
116+
trend=150,
117+
stop_loss_percentage=7
106118
),
107119
create_algorithm(
108120
name="20-75-200",
109121
description="20-75-200",
110122
fast=20,
111123
slow=75,
112-
trend=200
124+
trend=200,
125+
stop_loss_percentage=7
113126
),
114127
create_algorithm(
115128
name="21-75-200",
116129
description="24-75-200",
117130
fast=24,
118131
slow=75,
119-
trend=200
132+
trend=200,
133+
stop_loss_percentage=7
120134
),
121135
create_algorithm(
122136
name="22-75-200",
123137
description="24-75-200",
124138
fast=24,
125139
slow=75,
126-
trend=200
140+
trend=200,
141+
stop_loss_percentage=7
127142
),
128143
create_algorithm(
129144
name="23-75-200",
130145
description="24-75-200",
131146
fast=24,
132147
slow=75,
133-
trend=200
148+
trend=200,
149+
stop_loss_percentage=7
134150
),
135151
create_algorithm(
136152
name="24-75-200",
137153
description="24-75-200",
138154
fast=24,
139155
slow=75,
140-
trend=200
156+
trend=200,
157+
stop_loss_percentage=7
141158
),
142159
create_algorithm(
143160
name="25-75-150",
144161
description="25-75-200",
145162
fast=25,
146163
slow=75,
147-
trend=200
164+
trend=200,
165+
stop_loss_percentage=7
148166
),
149167
],
150168
start_date=start_date,

investing_algorithm_framework/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
Trade, OHLCVMarketDataSource, OrderBookMarketDataSource, SYMBOLS, \
99
TickerMarketDataSource, MarketService, BacktestReportsEvaluation, \
1010
pretty_print_backtest_reports_evaluation, load_backtest_reports, \
11-
RESERVED_BALANCES, APP_MODE, AppMode
11+
RESERVED_BALANCES, APP_MODE, AppMode, DATETIME_FORMAT
1212
from investing_algorithm_framework.app import TradingStrategy, \
1313
StatelessAction, Task
1414
from investing_algorithm_framework.infrastructure import \
@@ -59,5 +59,6 @@
5959
"SYMBOLS",
6060
"RESERVED_BALANCES",
6161
"APP_MODE",
62-
"AppMode"
62+
"AppMode",
63+
"DATETIME_FORMAT",
6364
]

investing_algorithm_framework/app/app.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,13 @@ def initialize(self, sync=False):
109109
trade_service=self.container.trade_service(),
110110
)
111111

112-
if self._stateless:
113-
self.config[APP_MODE] = AppMode.STATELESS.value
114-
elif self._web:
115-
self.config[APP_MODE] = AppMode.WEB.value
116-
else:
117-
self.config[APP_MODE] = AppMode.DEFAULT.value
112+
if APP_MODE not in self.config:
113+
if self._stateless:
114+
self.config[APP_MODE] = AppMode.STATELESS.value
115+
elif self._web:
116+
self.config[APP_MODE] = AppMode.WEB.value
117+
else:
118+
self.config[APP_MODE] = AppMode.DEFAULT.value
118119

119120
if AppMode.WEB.from_value(self.config[APP_MODE]):
120121
self._initialize_web()
@@ -460,7 +461,7 @@ def run(
460461
for hook in self._on_after_initialize_hooks:
461462
hook.on_run(self, self.algorithm)
462463

463-
self.initialize()
464+
self.initialize(sync=sync)
464465

465466
# Run all on_initialize hooks
466467
for hook in self._on_initialize_hooks:

investing_algorithm_framework/domain/services/market_service.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import logging
2+
from typing import Dict
23
from abc import ABC, abstractmethod
34
from datetime import datetime
4-
5+
from polars import DataFrame
56
logger = logging.getLogger("investing_algorithm_framework")
67

78

@@ -98,13 +99,13 @@ def get_closed_orders(
9899
@abstractmethod
99100
def get_ohlcv(
100101
self, symbol, time_frame, from_timestamp, market, to_timestamp=None
101-
):
102+
) -> DataFrame:
102103
raise NotImplementedError()
103104

104105
@abstractmethod
105106
def get_ohlcvs(
106107
self, symbols, time_frame, from_timestamp, market, to_timestamp=None
107-
):
108+
) -> Dict[str, DataFrame]:
108109
raise NotImplementedError()
109110

110111
@property

investing_algorithm_framework/infrastructure/models/market_data_sources/ccxt.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ def get_data(self, **kwargs):
370370
first_row = df.head(1)[0]
371371

372372
if first_row["Datetime"][0] > end_date.strftime(DATETIME_FORMAT):
373-
logger.warn(
373+
logger.warning(
374374
f"No ticker data available for the given backtest "
375375
f"index date {backtest_index_date} and symbol {self.symbol} "
376376
f"and market {self.market}"

investing_algorithm_framework/infrastructure/services/market_service/ccxt_market_service.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import logging
2+
from typing import Dict
23
from datetime import datetime
34
from time import sleep
4-
5+
import polars as pl
56
import ccxt
67
from dateutil import parser
78
from dateutil.tz import gettz
@@ -341,7 +342,7 @@ def get_closed_orders(
341342

342343
def get_ohlcv(
343344
self, symbol, time_frame, from_timestamp, market, to_timestamp=None
344-
):
345+
) -> pl.DataFrame:
345346
market_credential = self.get_market_credential(market)
346347
exchange = self.initialize_exchange(market, market_credential)
347348

@@ -388,7 +389,15 @@ def get_ohlcv(
388389

389390
sleep(exchange.rateLimit / 1000)
390391

391-
return data
392+
# Predefined column names
393+
col_names = ["Datetime", "Open", "High", "Low", "Close", "Volume"]
394+
395+
# Combine the Series into a DataFrame with given column names
396+
df = pl.DataFrame(data)
397+
398+
# Assign column names after DataFrame creation
399+
df.columns = col_names
400+
return df
392401

393402
def get_ohlcvs(
394403
self,
@@ -397,7 +406,7 @@ def get_ohlcvs(
397406
from_timestamp,
398407
market,
399408
to_timestamp=None
400-
):
409+
) -> Dict[str, pl.DataFrame]:
401410
ohlcvs = {}
402411

403412
for symbol in symbols:

0 commit comments

Comments
 (0)