Moving averages crossover is one of the simplest trend following strategy. We have two moving averages, the faster one is say 9 day average, while the slower one is 21 day average. We buy when the fast MA moves above slow MA, and sell when the slow MA moves above the fast MA. This simple strategy is coded for the LNMarketBot as:
import time
import talib
import datetime
from LNMarketBot import Strategy, BacktestBroker, CSVData, Bot
class MACrossStrat(Strategy):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def init(self):
return
def execute(self, datas):
dtime = datas[1].index
close = datas[1]["close"]
fastsma = talib.SMA(close, timeperiod=self.params["FastPeriod"])
slowsma = talib.SMA(close, timeperiod=self.params["SlowPeriod"])
fastOverSlow = fastsma[-1] > slowsma[-1]
assert(self.broker is not None)
leverage = self.params['Leverage']
riskAmount = round(self.broker.balance*self.params["RiskPercent"])
if self.position <= 0 and fastOverSlow:
self.broker.notifier.notify(
f"{dtime[-1]} Pos: {self.position} "
f"fastsma: {fastsma[-1]:.2f} "
f"slowsma: {slowsma[-1]:.2f}"
)
quantity = riskAmount // close[-1] - self.position
self.broker.buy(
strategy=self,
leverage=leverage,
quantity=quantity,
)
if self.position >= 0 and not fastOverSlow:
self.broker.notifier.notify(
f"{dtime[-1]} Pos: {self.position} "
f"fastsma: {fastsma[-1]:.2f} "
f"slowsma: {slowsma[-1]:.2f}"
)
quantity = riskAmount // close[-1] + self.position
self.broker.sell(
strategy=self,
leverage=leverage,
quantity=quantity,
)
def stop(self):
self.broker.notifier.notify(f"Final Gain: {(self.broker.balance-self.initialCapital)/self.initialCapital:.2f}")
self.broker.notifier.notify(f"Max Drawdown {self.maxdrawdown:.2f}")
self.broker.notifier.notify(self.broker.transactions)
self.broker.notifier.notify(f"Time taken:{time.perf_counter()-self.startTime:.2f}")
The class MACrossStrat
extends the Strategy
class. It needs to provide three methods init()
which runs at the start of strategy execution, execute()
which runs at every new price bar, and stop()
which runs when the strategy has finished. The strategy takes FastPeriod and SlowPeriod, as parameters, which control the time periods of moving averages. These parameters, among others like Leverage and RiskPercent are passed when the strategy is initialised. The following code creates the broker and Data objects and attaches them to the strategy. The strategy is then given to bot to run.
broker = BacktestBroker(1.0e06)
broker.notifier.enableStdout()
dirname = '../../'
filename = 'BTCPriceData2015.csv'
filename1 = 'BTCPriceData2015Daily.csv'
csvdata = CSVData(
dirname+filename,
window=datetime.timedelta(days=31),
datetime='Unnamed: 0',
)
csvdata1 = CSVData(
dirname+filename1,
window=datetime.timedelta(days=31),
datetime='Unnamed: 0',
)
strategy = MACrossStrat(
broker=broker,
FastPeriod=9,
SlowPeriod=21,
RiskPercent=0.1,
Leverage=1,
)
strategy.addData(csvdata)
strategy.addData(csvdata1)
bot = Bot()
bot.addStrategy(strategy)
bot.run()