@@ -73,18 +73,30 @@ This will create:
7373---
7474
7575## 📈 Example: A Simple Trading Bot
76- The following example connects to Binance and buys BTC every 2 hours.
76+ The following example trading bot implements a simple moving average strategy.
77+ The strategy will use data from bitvavo exchange and will calculate
78+ the 20, 50 and 100 period exponential moving averages (EMA) and the
79+ 14 period relative strength index (RSI).
80+
81+ > This example uses [ PyIndicators] ( https://github.com/coding-kitties/pyindicators ) for technical analysis.
82+ > This dependency is not part of the framework, but is used to perform technical analysis on the dataframes.
83+ > You can install it using pip: pip install pyindicators.
84+
85+ ``` bash
7786
7887` ` ` python
7988import logging.config
8089from dotenv import load_dotenv
8190
91+ from pyindicators import ema, rsi
92+
8293from investing_algorithm_framework import create_app, TimeUnit, Context, BacktestDateRange, \
8394 CCXTOHLCVMarketDataSource, CCXTTickerMarketDataSource, DEFAULT_LOGGING_CONFIG, \
84- TradingStrategy, SnapshotInterval
95+ TradingStrategy, SnapshotInterval, convert_polars_to_pandas
8596
8697load_dotenv ()
8798logging.config.dictConfig(DEFAULT_LOGGING_CONFIG)
99+ logger = logging.getLogger(__name__)
88100
89101# OHLCV data for candles
90102bitvavo_btc_eur_ohlcv_2h = CCXTOHLCVMarketDataSource(
@@ -111,21 +123,58 @@ class MyStrategy(TradingStrategy):
111123 data_sources = [bitvavo_btc_eur_ohlcv_2h, bitvavo_btc_eur_ticker]
112124
113125 def run_strategy(self, context: Context, market_data):
114- # Access the data sources with the indentifier
115- polars_df = market_data[" BTC-ohlcv" ]
116- ticker_data = market_data[" BTC-ticker" ]
117- unallocated_balance = context.get_unallocated()
118- positions = context.get_positions()
119- trades = context.get_trades()
120- open_trades = context.get_open_trades()
121- closed_trades = context.get_closed_trades()
126+
127+ if context.has_open_orders(target_symbol=" BTC" ):
128+ logger.info(" There are open orders, skipping strategy iteration." )
129+ return
130+
131+ print(market_data)
132+
133+ data = convert_polars_to_pandas(market_data[" BTC-ohlcv" ])
134+ data = ema(data, source_column=" Close" , period=20, result_column=" ema_20" )
135+ data = ema(data, source_column=" Close" , period=50, result_column=" ema_50" )
136+ data = ema(data, source_column=" Close" , period=100, result_column=" ema_100" )
137+ data = rsi(data, source_column=" Close" , period=14, result_column=" rsi_14" )
138+
139+ if context.has_position(" BTC" ) and self.sell_signal(data):
140+ context.create_limit_sell_order(
141+ " BTC" , percentage_of_position=100, price=data[" Close" ].iloc[-1]
142+ )
143+ return
144+
145+ if not context.has_position(" BTC" ) and self.buy_signal(data):
146+ context.create_limit_buy_order(
147+ " BTC" , percentage_of_portfolio=20, price=data[" Close" ].iloc[-1]
148+ )
149+ return
150+
151+ def buy_signal(self, data):
152+ if len(data) < 100:
153+ return False
154+ last_row = data.iloc[-1]
155+ if last_row[" ema_20" ] > last_row[" ema_50" ] and last_row[" ema_50" ] > last_row[" ema_100" ]:
156+ return True
157+ return False
158+
159+ def sell_signal(self, data):
160+
161+ if data[" ema_20" ].iloc[-1] < data[" ema_50" ].iloc[-1] and \
162+ data[" ema_20" ].iloc[-2] > = data[" ema_50" ].iloc[-2]:
163+ return True
164+
165+ return False
122166
123167date_range = BacktestDateRange(
124- start_date = " 2023-08-24 00:00:00" ,
125- end_date = " 2023-12-02 00:00:00"
168+ start_date=" 2023-08-24 00:00:00" , end_date=" 2023-12-02 00:00:00"
126169)
127- backtest_report = app.run_backtest(backtest_date_range = date_range, initial_amount = 100 , snapshot_interval = SnapshotInterval.STRATEGY_ITERATION )
128- backtest_report.show()
170+ app.add_strategy(MyStrategy)
171+
172+ if __name__ == " __main__" :
173+ # Run the backtest with a daily snapshot interval for end-of-day granular reporting
174+ backtest_report = app.run_backtest(
175+ backtest_date_range=date_range, initial_amount=100, snapshot_interval=SnapshotInterval.STRATEGY_ITERATION
176+ )
177+ backtest_report.show ()
129178` ` `
130179
131180> You can find more examples [here](./examples) folder.
0 commit comments