Skip to content

Commit fb30e63

Browse files
committed
Refactor to persistent trade service
1 parent e7d0710 commit fb30e63

File tree

81 files changed

+20073
-25344
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+20073
-25344
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
strategy:
4141
fail-fast: true
4242
matrix:
43-
os: [ "ubuntu-latest", "macos-latest" ]
43+
os: [ "ubuntu-latest", "macos-latest", "windows-latest" ]
4444
python-version: [ "3.8", "3.9", "3.10", "3.11" ]
4545
runs-on: ${{ matrix.os }}
4646
steps:

README.md

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ Features:
3737
The following algorithm connects to binance and buys BTC every 5 seconds. It also exposes an REST API that allows you to interact with the algorithm.
3838

3939
```python
40-
import logging
4140
import logging.config
4241

4342
from investing_algorithm_framework import create_app, PortfolioConfiguration, \
@@ -90,24 +89,21 @@ def perform_strategy(algorithm: Algorithm, market_data: dict):
9089
closed_trades = algorithm.get_closed_trades()
9190

9291
# Create a buy oder
93-
trade = algorithm.create_limit_order(
92+
order = algorithm.create_limit_order(
9493
target_symbol="BTC/EUR",
9594
order_side="buy",
9695
amount=0.01,
9796
price=ticker_data["ask"],
9897
)
99-
100-
# Add a stop loss percentage of 5%
101-
algorithm.add_stop_loss(trade.id, percentage=5)
102-
103-
# Add a take profit percentage of 10%
104-
algorithm.add_take_profit(trade.id, percentage=5)
98+
trade = algorithm.get_trade(order_id=order.id)
99+
algorithm.add_trailing_stop_loss(trade=trade, percentage=5)
105100

106101
# Close a trade
107-
algorithm.close_trade(trades[0].id)
102+
algorithm.close_trade(trade=trade)
108103

109104
# Close a position
110-
algorithm.close_position(positions[0].get_symbol())
105+
position = algorithm.get_position(symbol="BTC/EUR")
106+
algorithm.close_position(position)
111107

112108
if __name__ == "__main__":
113109
app.run()
@@ -119,7 +115,14 @@ if __name__ == "__main__":
119115

120116
The framework also supports backtesting and performing backtest experiments. After a backtest, you can print a report that shows the performance of your trading bot.
121117

122-
To run a single backtest you can use the example code that can be found [here](./examples/backtest).
118+
To run a single backtest you can use the example code that can be found [here](./examples/backtest_example). Simply run:
119+
120+
> Its assumed here that you have cloned the repository, installed the framework and
121+
> are in the root of the project.
122+
123+
```bash
124+
python examples/backtest_example/run_backtest.py
125+
```
123126

124127
### Backtesting report
125128

examples/backtest_example/__init__.py

Whitespace-only changes.

examples/backtest_example/algorithm/__init__.py

Whitespace-only changes.

examples/backtest_example/algorithm/algorithm.py

Lines changed: 0 additions & 5 deletions
This file was deleted.

examples/backtest_example/algorithm/data_sources.py

Lines changed: 0 additions & 30 deletions
This file was deleted.

examples/backtest_example/algorithm/strategy.py

Lines changed: 0 additions & 108 deletions
This file was deleted.

examples/backtest_example/app.py

Lines changed: 0 additions & 11 deletions
This file was deleted.

examples/backtest_example/run_backtest.py

Lines changed: 138 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,150 @@
1+
import logging.config
12
from datetime import datetime, timedelta
23

3-
from algorithm.algorithm import algorithm
4-
from algorithm.data_sources import bitvavo_btc_eur_ohlcv_2h, \
5-
bitvavo_dot_eur_ohlcv_2h, bitvavo_dot_eur_ticker, bitvavo_btc_eur_ticker
6-
from app import app
7-
from investing_algorithm_framework import PortfolioConfiguration, \
8-
pretty_print_backtest, BacktestDateRange
94

5+
from investing_algorithm_framework import CCXTOHLCVMarketDataSource, \
6+
CCXTTickerMarketDataSource, Algorithm, PortfolioConfiguration, \
7+
create_app, pretty_print_backtest, BacktestDateRange, TimeUnit, \
8+
TradingStrategy, OrderSide, DEFAULT_LOGGING_CONFIG
9+
10+
import tulipy as ti
11+
12+
logging.config.dictConfig(DEFAULT_LOGGING_CONFIG)
13+
14+
15+
"""
16+
This strategy is based on the golden cross strategy. It will buy when the
17+
fast moving average crosses the slow moving average from below. It will sell
18+
when the fast moving average crosses the slow moving average from above.
19+
The strategy will also check if the fast moving average is above the trend
20+
moving average. If it is not above the trend moving average it will not buy.
21+
22+
It uses tulipy indicators to calculate the metrics. You need to
23+
install this library in your environment to run this strategy.
24+
You can find instructions on how to install tulipy here:
25+
https://tulipindicators.org/ or go directly to the pypi page:
26+
https://pypi.org/project/tulipy/
27+
"""
28+
29+
bitvavo_btc_eur_ohlcv_2h = CCXTOHLCVMarketDataSource(
30+
identifier="BTC/EUR-ohlcv",
31+
market="BINANCE",
32+
symbol="BTC/EUR",
33+
time_frame="2h",
34+
window_size=200
35+
)
36+
bitvavo_dot_eur_ohlcv_2h = CCXTOHLCVMarketDataSource(
37+
identifier="DOT/EUR-ohlcv",
38+
market="BINANCE",
39+
symbol="DOT/EUR",
40+
time_frame="2h",
41+
window_size=200
42+
)
43+
bitvavo_dot_eur_ticker = CCXTTickerMarketDataSource(
44+
identifier="DOT/EUR-ticker",
45+
market="BINANCE",
46+
symbol="DOT/EUR",
47+
backtest_time_frame="2h",
48+
)
49+
bitvavo_btc_eur_ticker = CCXTTickerMarketDataSource(
50+
identifier="BTC/EUR-ticker",
51+
market="BINANCE",
52+
symbol="BTC/EUR",
53+
backtest_time_frame="2h",
54+
)
55+
56+
57+
def is_below_trend(fast_series, slow_series):
58+
return fast_series[-1] < slow_series[-1]
59+
60+
61+
def is_above_trend(fast_series, slow_series):
62+
return fast_series[-1] > slow_series[-1]
63+
64+
65+
def is_crossover(fast, slow):
66+
"""
67+
Expect df to have columns: Date, ma_<period_one>, ma_<period_two>.
68+
With the given date time it will check if the ma_<period_one> is a
69+
crossover with the ma_<period_two>
70+
"""
71+
return fast[-2] <= slow[-2] and fast[-1] > slow[-1]
72+
73+
74+
def is_crossunder(fast, slow):
75+
"""
76+
Expect df to have columns: Date, ma_<period_one>, ma_<period_two>.
77+
With the given date time it will check if the ma_<period_one> is a
78+
crossover with the ma_<period_two>
79+
"""
80+
return fast[-2] >= slow[-2] and fast[-1] < slow[-1]
81+
82+
83+
class CrossOverStrategy(TradingStrategy):
84+
time_unit = TimeUnit.HOUR
85+
interval = 2
86+
market_data_sources = [
87+
bitvavo_dot_eur_ticker,
88+
bitvavo_btc_eur_ticker,
89+
bitvavo_dot_eur_ohlcv_2h,
90+
bitvavo_btc_eur_ohlcv_2h
91+
]
92+
symbols = ["BTC/EUR", "DOT/EUR"]
93+
fast = 21
94+
slow = 75
95+
trend = 150
96+
stop_loss_percentage = 7
97+
98+
def apply_strategy(self, algorithm: Algorithm, market_data):
99+
100+
for symbol in self.symbols:
101+
target_symbol = symbol.split('/')[0]
102+
103+
if algorithm.has_open_orders(target_symbol):
104+
continue
105+
106+
df = market_data[f"{symbol}-ohlcv"]
107+
ticker_data = market_data[f"{symbol}-ticker"]
108+
fast = ti.sma(df['Close'].to_numpy(), self.fast)
109+
slow = ti.sma(df['Close'].to_numpy(), self.slow)
110+
trend = ti.sma(df['Close'].to_numpy(), self.trend)
111+
price = ticker_data["bid"]
112+
113+
if not algorithm.has_position(target_symbol) \
114+
and is_crossover(fast, slow) \
115+
and is_above_trend(fast, trend):
116+
order = algorithm.create_limit_order(
117+
target_symbol=target_symbol,
118+
order_side=OrderSide.BUY,
119+
price=price,
120+
percentage_of_portfolio=25,
121+
precision=4,
122+
)
123+
trade = algorithm.get_trade(order_id=order.id)
124+
algorithm.add_trailing_stop_loss(
125+
trade=trade, percentage=5
126+
)
127+
128+
129+
if algorithm.has_position(target_symbol) \
130+
and is_below_trend(fast, slow):
131+
open_trades = algorithm.get_open_trades(
132+
target_symbol=target_symbol
133+
)
134+
135+
for trade in open_trades:
136+
algorithm.close_trade(trade)
137+
138+
139+
app = create_app()
140+
algorithm = Algorithm("GoldenCrossStrategy")
141+
algorithm.add_strategy(CrossOverStrategy)
10142
app.add_algorithm(algorithm)
11143
app.add_market_data_source(bitvavo_btc_eur_ohlcv_2h)
12144
app.add_market_data_source(bitvavo_dot_eur_ohlcv_2h)
13145
app.add_market_data_source(bitvavo_btc_eur_ticker)
14146
app.add_market_data_source(bitvavo_dot_eur_ticker)
15147

16-
17148
# Add a portfolio configuration of 400 euro initial balance
18149
app.add_portfolio_configuration(
19150
PortfolioConfiguration(

examples/backtests_example/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)