| Overall Statistics |
|
Total Trades 444 Average Win 3.01% Average Loss -3.05% Compounding Annual Return 41.443% Drawdown 45.800% Expectancy 0.645 Net Profit 5052.541% Sharpe Ratio 1.119 Probabilistic Sharpe Ratio 40.083% Loss Rate 17% Win Rate 83% Profit-Loss Ratio 0.99 Alpha 0 Beta 0 Annual Standard Deviation 0.371 Annual Variance 0.138 Information Ratio 1.119 Tracking Error 0.371 Treynor Ratio 0 Total Fees $7766.06 Estimated Strategy Capacity $490000.00 |
class HABBRStrategy (QCAlgorithm):
def Initialize (self):
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
self.SetStartDate(2010, 1, 1)
self.SetEndDate(2021, 12, 31)
self.SetCash(100000)
self.symbols = [
# 'EURUSD','AUDCAD','NZDCHF','EURAUD','NZDCAD','AUDJPY','AUDCHF',
# 'GBPCAD','EURJPY','EURCAD','CADCHF','GBPCHF','NZDJPY','USDCHF',
# 'CHFJPY','AUDNZD'
# 'AUDNZD'
'EURUSD','AUDCHF','AUDJPY','AUDNZD','AUDUSD','CADCHF','CADJPY',
'CHFJPY','EURAUD','EURCAD','EURCHF','EURGBP','EURJPY','EURNZD',
'EURUSD','GBPAUD','GBPCAD','GBPCHF','GBPJPY','GBPNZD','GBPUSD',
'NZDCAD','NZDCHF','NZDJPY','NZDUSD','USDCAD','USDCHF','USDJPY'
]
haPeriod = 500
haStdev = 2
rsiPeriod = 20
self.SetWarmUp(max(haPeriod, rsiPeriod))
self.ha = {}
self.bb = {}
self.rsi = {}
self.pb = {}
self.overSold = {}
self.overBought = {}
self.orders = {}
# % of BB bandwidth entry above/below limit
self.longEntry = 0.382
self.longExit = 1.0
self.shortEntry = 0.618
self.shortExit = 0.0
# % loss before position closed
self.lossLimit = -25
for symbol in self.symbols:
Symbol = self.AddForex(symbol, Resolution.Daily, Market.Oanda).Symbol
self.pb[symbol] = RollingWindow[float](2)
self.ha[symbol] = self.HeikinAshi(Symbol)
self.bb[symbol] = IndicatorExtensions.Of(self.BB(Symbol, haPeriod, haStdev), self.ha[symbol])
self.bb[symbol].Updated += self.bbUpdated
self.rsi[symbol] = self.RSI(Symbol, rsiPeriod)
self.overSold[symbol] = False
self.overBought[symbol] = False
def bbUpdated (self, sender, updated):
self.Debug(str(sender))
for symbol in self.symbols:
bb = self.bb[symbol]
self.pb[symbol].Add(bb.PercentB.Current.Value)
def OnData (self, data):
for symbol in self.symbols:
if self.IsWarmingUp or not (
self.ha[symbol].IsReady or
self.bb[symbol].IsReady or
self.rsi[symbol].IsReady or
self.pb[symbol].IsReady
): return
ha = self.ha[symbol]
bb = self.bb[symbol]
open = ha.Open.Current.Value
high = ha.High.Current.Value
low = ha.Low.Current.Value
close = ha.Close.Current.Value
percB = bb.PercentB.Current.Value
percB1 = self.pb[symbol][1]
rsi = self.rsi[symbol].Current.Value
if percB1 < self.longEntry / 2:
self.overSold[symbol] = True
elif percB1 > (1 - self.shortEntry) / 2 + self.shortEntry:
self.overBought[symbol] = True
bbVal = str(round(percB, 2))
rsiVal = str(round(rsi, 1))
qty = self.CalculateOrderQuantity(symbol, 1)
if not self.Portfolio[symbol].Invested:
isLongSignal = self.overSold[symbol] and percB > self.longEntry and rsi < 40
isShortSignal = self.overBought[symbol] and percB < self.shortEntry and rsi > 60
if isLongSignal:
self.orders[symbol] = self.MarketOrder(symbol, qty, False, f'ENTER long {bbVal} {rsiVal}')
self.overSold[symbol] = False
elif isShortSignal:
self.orders[symbol] = self.MarketOrder(symbol, -qty, False, f'ENTER short {bbVal} {rsiVal}')
self.overBought[symbol] = False
else:
isLong = self.Portfolio[symbol].IsLong
isShort = self.Portfolio[symbol].IsShort
direction = 'long' if isLong else 'short'
entryPrice = self.orders[symbol].AverageFillPrice
currentPrice = data[symbol].Close
loss = (currentPrice - entryPrice if isLong else entryPrice - currentPrice) / entryPrice * 100
if loss < self.lossLimit:
self.Liquidate(symbol, f'EXIT LOSS {direction} {bbVal} {loss}')
elif (isLong and percB > self.longExit) or (isShort and percB < self.shortExit):
self.Liquidate(symbol, f'EXIT {direction} {bbVal}')from datetime import timedelta
import numpy as np
class HABBRStrategy(QCAlgorithm):
def Initialize(self):
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
self.SetStartDate(2010, 1, 1)
self.SetEndDate(2021, 12, 31)
self.SetCash(100000)
self.symbols = [
# 'AUDCAD'
'AUDCAD','AUDCHF','AUDJPY','AUDNZD','AUDUSD','CADCHF','CADJPY',
'CHFJPY','EURAUD','EURCAD','EURCHF','EURGBP','EURJPY','EURNZD',
'EURUSD','GBPAUD','GBPCAD','GBPCHF','GBPJPY','GBPNZD','GBPUSD',
'NZDCAD','NZDCHF','NZDJPY','NZDUSD','USDCAD','USDCHF','USDJPY'
]
n = 500
self.SetWarmUp(n)
self.ha = {}
self.bb = {}
self.rsi = {}
self.windowBBPercB = {}
self.overSold = {}
self.overBought = {}
self.orders = {}
# % of BB bandwidth entry above/below limit
self.longEntry = 0.382
self.longExit = 1.0
self.shortEntry = 0.618
self.shortExit = 0.0
for symbol in self.symbols:
self.AddForex(symbol, Resolution.Daily, Market.Oanda)
self.ha[symbol] = self.HeikinAshi(symbol)
self.bb[symbol] = IndicatorExtensions.Of(self.BB(symbol, n, 2), self.ha[symbol])
self.bb[symbol].Updated += self.bbUpdated
self.rsi[symbol] = self.RSI(symbol, 20)
self.overSold[symbol] = False
self.overBought[symbol] = False
self.windowBBPercB[symbol] = RollingWindow[float](2)
def bbUpdated (self, sender, updated):
for symbol in self.symbols:
bb = self.bb[symbol]
self.windowBBPercB[symbol].Add(bb.PercentB.Current.Value)
def OnData (self, data):
if self.IsWarmingUp: return
for symbol in self.symbols:
ha = self.ha[symbol]
bb = self.bb[symbol]
open = ha.Open.Current.Value
high = ha.High.Current.Value
low = ha.Low.Current.Value
close = ha.Close.Current.Value
percB = bb.PercentB.Current.Value
percB1 = self.windowBBPercB[symbol][1]
rsi = self.rsi[symbol].Current.Value
self.Debug(rsi)
if percB1 < self.longEntry / 2:
self.overSold[symbol] = True
elif percB1 > (1 - self.shortEntry) / 2 + self.shortEntry:
self.overBought[symbol] = True
bbVal = str(round(percB, 2))
rsiVal = str(round(rsi, 1))
qty = self.CalculateOrderQuantity(symbol, 1)
if not self.Portfolio[symbol].Invested:
isLongSignal = self.overSold[symbol] and percB > self.longEntry and rsi < 40
isShortSignal = self.overBought[symbol] and percB < self.shortEntry and rsi > 60
if isLongSignal:
self.orders[symbol] = self.MarketOrder(symbol, qty, False, f'ENTER long {bbVal} {rsiVal}')
self.overSold[symbol] = False
elif isShortSignal:
self.orders[symbol] = self.MarketOrder(symbol, -qty, False, f'ENTER short {bbVal} {rsiVal}')
self.overBought[symbol] = False
else:
isLong = self.Portfolio[symbol].IsLong
isShort = self.Portfolio[symbol].IsShort
direction = 'long' if isLong else 'short'
entryPrice = self.orders[symbol].AverageFillPrice
currentPrice = data[symbol].Close
loss = (currentPrice - entryPrice if isLong else entryPrice - currentPrice) / entryPrice * 100
if loss < -25:
self.Liquidate(symbol, f'EXIT LOSS {direction} {bbVal}')
elif (isLong and percB > self.longExit) or (isShort and percB < self.shortExit):
self.Liquidate(symbol, f'EXIT {direction} {bbVal}')from datetime import datetime
import decimal
import numpy as np
# Heikin Ashi Bollinger Bands Reversion (HABBR) Strategy
class HABBR (QCAlgorithm):
def Initialize (self):
# self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
self.SetStartDate(2020, 10, 1)
self.SetEndDate(2021, 12, 31)
self.SetCash(100000)
# available pairs for modelling
# AUDCAD, AUDCHF, AUDJPY, AUDNZD, AUDUSD, CADCHF, CADJPY
# CHFJPY, EURAUD, EURCAD, EURCHF, EURGBP, EURJPY, EURNZD
# EURUSD, GBPAUD, GBPCAD, GBPCHF, GBPJPY, GBPNZD, GBPUSD
# NZDCAD, NZDCHF, NZDJPY, NZDUSD, USDCAD, USDCHF, USDJPY
fx = self.AddForex('AUDCAD', Resolution.Hour, Market.Oanda)
self.syl = fx.Symbol
self.Schedule.On(self.DateRules.EveryDay(self.syl), self.TimeRules.BeforeMarketClose(self.syl, 1), Action(self.SetSignal))
self.overBought, self.overSold = False, False
self.SetBenchmark(self.syl)
self.Bolband = self.BB(self.syl, 20, 2, MovingAverageType.Simple, Resolution.Daily)
def OnData (self, data):
close = self.History(self.syl, 1, Resolution.Daily)['close']
self.yesterdayclose = close.iloc[-1]
# wait for our BollingerBand to fully initialize
if not self.Bolband.IsReady: return
holdings = self.Portfolio[self.syl].Quantity
if self.yesterdayclose > self.Bolband.UpperBand.Current.Value:
self.overBought = True
self.overSold = False
elif self.yesterdayclose < self.Bolband.LowerBand.Current.Value:
self.overSold = True
self.overBought = False
if self.overBought and self.yesterdayclose < self.Bolband.MiddleBand.Current.Value:
self.SetHoldings(self.syl, -1)
self.overBought = False
elif self.overSold and self.yesterdayclose > self.Bolband.MiddleBand.Current.Value:
self.SetHoldings(self.syl, 1)
self.overSold = False
if holdings > 0 and self.yesterdayclose < self.Bolband.MiddleBand.Current.Value:
self.Liquidate(self.syl)
elif holdings < 0 and self.yesterdayclose > self.Bolband.MiddleBand.Current.Value:
self.Liquidate(self.syl)import decimal as d
import numpy as np
class heikinAshiExample(QCAlgorithm):
def Initialize(self):
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
self.SetStartDate(2019, 1, 1)
self.SetEndDate(2020, 12, 31)
self.SetCash(100000)
self.SetWarmUp(20)
self.symbols = [
'AUDCAD','AUDCHF','AUDJPY','AUDNZD','AUDUSD','CADCHF','CADJPY',
'CHFJPY','EURAUD','EURCAD','EURCHF','EURGBP','EURJPY','EURNZD',
'EURUSD','GBPAUD','GBPCAD','GBPCHF','GBPJPY','GBPNZD','GBPUSD',
'NZDCAD','NZDCHF','NZDJPY','NZDUSD','USDCAD','USDCHF','USDJPY'
]
self.ha = {}
self.bb = {}
self.windowHAClose = {}
self.windowBBUpper = {}
self.windowBBMiddle = {}
self.windowBBLower = {}
self.overSold = {}
self.overBought = {}
self.consolidators = {}
# % of BB bandwitdh for stop loss/entry above/below limit
# self.longStopLoss = -0.20
self.longEntry = 0.4
self.longExit = 1.0
# self.shortStopLoss = 1.20
self.shortEntry = 0.6
self.shortExit = 0.0
for symbol in self.symbols:
Symbol = self.AddForex(symbol, Resolution.Hour, Market.Oanda).Symbol
self.ha[symbol] = self.HeikinAshi(Symbol, Resolution.Daily)
self.bb[symbol] = IndicatorExtensions.Of(
self.BB(Symbol, 20, 2, MovingAverageType.Simple, Resolution.Daily),
self.ha[symbol]
)
self.overSold[symbol] = False
self.overBought[symbol] = False
self.ha[symbol].Updated += self.haUpdated
self.bb[symbol].Updated += self.bbUpdated
self.windowHAClose[symbol] = RollingWindow[float](3)
self.windowBBUpper[symbol] = RollingWindow[float](3)
self.windowBBMiddle[symbol] = RollingWindow[float](3)
self.windowBBLower[symbol] = RollingWindow[float](3)
## Oanda Forex opens 17:00 Sunday, closes Friday 17:00
self.Schedule.On(self.DateRules.On(2019, 1, 1), self.TimeRules.At(17, 0), self.DailyConsolidator)
# ==================================================================================================================
def DailyConsolidator (self):
for symbol in self.symbols:
self.consolidators[symbol] = QuoteBarConsolidator(24) # 24 hours | 1440 minutes | 86400 seconds
self.consolidators[symbol].DataConsolidated += self.OnDailyData
self.SubscriptionManager.AddConsolidator(symbol, self.consolidators[symbol])
# ==================================================================================================================
def haUpdated (self, sender, updated):
for symbol in self.symbols:
ha = self.ha[symbol]
self.windowHAClose[symbol].Add(ha.Close.Current.Value)
# ==================================================================================================================
def bbUpdated (self, sender, updated):
for symbol in self.symbols:
bb = self.bb[symbol]
self.windowBBUpper[symbol].Add(bb.UpperBand.Current.Value)
self.windowBBMiddle[symbol].Add(bb.MiddleBand.Current.Value)
self.windowBBLower[symbol].Add(bb.LowerBand.Current.Value)
# ==================================================================================================================
def OnDailyData (self, sender, consolidated):
if self.IsWarmingUp: return
for symbol in self.symbols:
open = self.ha[symbol].Open.Current.Value
high = self.ha[symbol].High.Current.Value
low = self.ha[symbol].Low.Current.Value
close = self.ha[symbol].Close.Current.Value
close1 = self.windowHAClose[symbol][1]
close2 = self.windowHAClose[symbol][2]
upper = self.bb[symbol].UpperBand.Current.Value
upper1 = self.windowBBUpper[symbol][1]
upper2 = self.windowBBUpper[symbol][2]
middle = self.bb[symbol].MiddleBand.Current.Value
lower = self.bb[symbol].LowerBand.Current.Value
lower1 = self.windowBBLower[symbol][1]
lower2 = self.windowBBLower[symbol][2]
bbPercentBandwidth = (close - lower) / (upper - lower)
bbPercentBandwidth1 = (close1 - lower1) / (upper1 - lower1)
bbPercentBandwidth2 = (close2 - lower2) / (upper2 - lower2)
# two preceding bars close outside BB range
if bbPercentBandwidth2 < 0 and bbPercentBandwidth1 < self.longEntry / 2 and bbPercentBandwidth < self.longEntry:
self.overSold[symbol] = True
elif bbPercentBandwidth2 > 1 and bbPercentBandwidth1 > (1 - self.shortEntry) / 2 + self.shortEntry and bbPercentBandwidth > self.shortEntry:
self.overBought[symbol] = True
if not self.Portfolio[symbol].Invested:
qty = self.Portfolio.TotalPortfolioValue
# longStopLoss = round(lower + lower * self.longStopLoss, 3)
# shortStopLoss = round(lower + lower * self.shortStopLoss, 3)
# LONG entry
if self.overSold[symbol] and bbPercentBandwidth > self.longEntry:
self.MarketOrder(symbol, qty, False, 'ENTER long')
# self.StopMarketOrder(symbol, -qty, longStopLoss, 'EXIT stop loss')
self.overSold[symbol] = False
# SHORT entry
elif self.overBought[symbol] and bbPercentBandwidth < self.shortEntry:
self.MarketOrder(symbol, -qty, False, 'ENTER short')
# self.StopMarketOrder(symbol, qty, shortStopLoss, 'EXIT stop loss')
self.overBought[symbol] = False
else:
is_long = self.Portfolio[symbol].IsLong
is_short = self.Portfolio[symbol].IsShort
if is_long and bbPercentBandwidth > self.longExit:
self.Liquidate(symbol, 'EXIT long')
# self.Transactions.CancelOpenOrders(symbol, 'Cancel limits/stop losses')
elif is_short and bbPercentBandwidth < self.shortExit:
self.Liquidate(symbol, 'EXIT short')
# self.Transactions.CancelOpenOrders(symbol, 'Cancel limits/stop losses')
# ==================================================================================================================
def OnData (self, data):
pass
# ==================================================================================================================
def OnOrderEvent (self, OrderEvent):
order = self.Transactions.GetOrderById(OrderEvent.OrderId)
symbol = OrderEvent.Symbol
# self.Debug(f'{OrderEvent}')
# if OrderEvent.Status == OrderStatus.Filled:
# if order.Type == OrderType.Limit:
# self.Transactions.CancelOpenOrders(symbol, 'Cancel stop loss')
# if order.Type == OrderType.StopMarket:
# self.Transactions.CancelOpenOrders(symbol, 'Cancel limit')
# ==================================================================================================================import decimal as d
import numpy as np
class heikinAshiExample(QCAlgorithm):
def Initialize(self):
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
self.SetStartDate(2017, 1, 1)
self.SetEndDate(2018, 12, 31)
self.SetCash(100000)
self.SetWarmUp(20)
self.symbols = [
'EURNZD'
# 'AUDCAD','AUDCHF','AUDJPY','AUDNZD','AUDUSD','CADCHF','CADJPY'
# 'CHFJPY','EURAUD','EURCAD','EURCHF','EURGBP','EURJPY','EURNZD'
# 'EURUSD','GBPAUD','GBPCAD','GBPCHF','GBPJPY','GBPNZD','GBPUSD'
# 'NZDCAD','NZDCHF','NZDJPY','NZDUSD','USDCAD','USDCHF','USDJPY'
]
self.ha = {}
self.bb = {}
self.windowHAClose = {}
self.windowBBUpper = {}
self.windowBBMiddle = {}
self.windowBBLower = {}
self.overSold = {}
self.overBought = {}
# % of BB bandwidth entry above/below limit
self.longEntry = 0.4
self.longExit = 1.0
self.shortEntry = 0.6
self.shortExit = 0.0
for symbol in self.symbols:
Symbol = self.AddForex(symbol, Resolution.Daily, Market.Oanda).Symbol
self.ha[symbol] = self.HeikinAshi(Symbol, Resolution.Daily)
self.bb[symbol] = IndicatorExtensions.Of(
self.BB(Symbol, 20, 2, MovingAverageType.Simple, Resolution.Daily),
self.ha[symbol]
)
self.overSold[symbol] = False
self.overBought[symbol] = False
self.ha[symbol].Updated += self.haUpdated
self.windowHAClose[symbol] = RollingWindow[float](3)
self.windowBBUpper[symbol] = RollingWindow[float](3)
self.windowBBMiddle[symbol] = RollingWindow[float](3)
self.windowBBLower[symbol] = RollingWindow[float](3)
def haUpdated (self, sender, updated):
for symbol in self.symbols:
ha = self.ha[symbol]
bb = self.bb[symbol]
self.windowHAClose[symbol].Add(ha.Close.Current.Value)
self.windowBBUpper[symbol].Add(bb.UpperBand.Current.Value)
self.windowBBMiddle[symbol].Add(bb.MiddleBand.Current.Value)
self.windowBBLower[symbol].Add(bb.LowerBand.Current.Value)
def OnData (self, data):
if self.IsWarmingUp: return
for symbol in self.symbols:
open = self.ha[symbol].Open.Current.Value
high = self.ha[symbol].High.Current.Value
low = self.ha[symbol].Low.Current.Value
close = self.ha[symbol].Close.Current.Value
close1 = self.windowHAClose[symbol][1]
close2 = self.windowHAClose[symbol][2]
upper = self.bb[symbol].UpperBand.Current.Value
upper1 = self.windowBBUpper[symbol][1]
upper2 = self.windowBBUpper[symbol][2]
middle = self.bb[symbol].MiddleBand.Current.Value
lower = self.bb[symbol].LowerBand.Current.Value
lower1 = self.windowBBLower[symbol][1]
lower2 = self.windowBBLower[symbol][2]
bbPercentBandwidth = (close - lower) / (upper - lower)
bbPercentBandwidth1 = (close1 - lower1) / (upper1 - lower1)
bbPercentBandwidth2 = (close2 - lower2) / (upper2 - lower2)
if bbPercentBandwidth2 < 0 and bbPercentBandwidth1 < self.longEntry / 2 and bbPercentBandwidth < self.longEntry:
self.overSold[symbol] = True
elif bbPercentBandwidth2 > 1 and bbPercentBandwidth1 > (1 - self.shortEntry) / 2 + self.shortEntry and bbPercentBandwidth > self.shortEntry:
self.overBought[symbol] = True
if not self.Portfolio[symbol].Invested:
# LONG entry
if self.overSold[symbol] and bbPercentBandwidth > self.longEntry:
self.SetHoldings(symbol, 1)
# self.MarketOrder(symbol, qty, False, 'ENTER long')
self.overSold[symbol] = False
# SHORT entry
elif self.overBought[symbol] and bbPercentBandwidth < self.shortEntry:
self.SetHoldings(symbol, -1)
# self.MarketOrder(symbol, -qty, False, 'ENTER short')
self.overBought[symbol] = False
else:
if self.Portfolio[symbol].IsLong and (bbPercentBandwidth > self.longExit):
self.Liquidate(symbol, 'EXIT long')
elif self.Portfolio[symbol].IsShort and (bbPercentBandwidth < self.shortExit):
self.Liquidate(symbol, 'EXIT short')from datetime import timedelta
import numpy as np
class HABBRStrategy(QCAlgorithm):
def Initialize(self):
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
self.SetStartDate(2021, 1, 1)
self.SetEndDate(2021, 12, 31)
self.SetCash(100000)
self.SetWarmUp(125)
self.symbols = [
# 'CADJPY'
'AUDCAD','AUDCHF','AUDJPY','AUDNZD','AUDUSD','CADCHF','CADJPY',
'CHFJPY','EURAUD','EURCAD','EURCHF','EURGBP','EURJPY','EURNZD',
'EURUSD','GBPAUD','GBPCAD','GBPCHF','GBPJPY','GBPNZD','GBPUSD',
'NZDCAD','NZDCHF','NZDJPY','NZDUSD','USDCAD','USDCHF','USDJPY'
]
self.ha = {}
self.bb = {}
self.windowHAClose = {}
self.windowBBUpper = {}
self.windowBBLower = {}
self.overSold = {}
self.overBought = {}
self.orders = {}
# % of BB bandwidth entry above/below limit
self.longEntry = 0.382
self.longExit = 1.0
self.shortEntry = 0.618
self.shortExit = 0.0
for symbol in self.symbols:
self.AddForex(symbol, Resolution.Daily, Market.Oanda)
self.ha[symbol] = self.HeikinAshi(symbol)
self.ha[symbol].Updated += self.haUpdated
self.bb[symbol] = IndicatorExtensions.Of(self.BB(symbol, 125, 2), self.ha[symbol])
self.overSold[symbol] = False
self.overBought[symbol] = False
self.windowHAClose[symbol] = RollingWindow[float](3)
self.windowBBUpper[symbol] = RollingWindow[float](3)
self.windowBBLower[symbol] = RollingWindow[float](3)
def haUpdated (self, sender, updated):
for symbol in self.symbols:
ha = self.ha[symbol]
bb = self.bb[symbol]
self.windowHAClose[symbol].Add(ha.Close.Current.Value)
self.windowBBUpper[symbol].Add(bb.UpperBand.Current.Value)
self.windowBBLower[symbol].Add(bb.LowerBand.Current.Value)
def OnData (self, data):
if self.IsWarmingUp: return
for symbol in self.symbols:
ha = self.ha[symbol]
bb = self.bb[symbol]
open = ha.Open.Current.Value
high = ha.High.Current.Value
low = ha.Low.Current.Value
close = ha.Close.Current.Value
upper = bb.UpperBand.Current.Value
lower = bb.LowerBand.Current.Value
close1 = self.windowHAClose[symbol][1]
upper1 = self.windowBBUpper[symbol][1]
lower1 = self.windowBBLower[symbol][1]
bbPercentBandwidth = (close - lower) / (upper - lower)
bbPercentBandwidth1 = (close1 - lower1) / (upper1 - lower1)
if bbPercentBandwidth1 < self.longEntry / 2 and bbPercentBandwidth < self.longEntry:
self.overSold[symbol] = True
elif bbPercentBandwidth1 > (1 - self.shortEntry) / 2 + self.shortEntry and bbPercentBandwidth > self.shortEntry:
self.overBought[symbol] = True
bbVal = str(round(bbPercentBandwidth, 2))
qty = self.CalculateOrderQuantity(symbol, 0.2)
if not self.Portfolio[symbol].Invested:
if self.overSold[symbol] and bbPercentBandwidth > self.longEntry: # LONG entry
self.orders[symbol] = self.MarketOrder(symbol, qty, False, f'ENTER long {bbVal}')
self.overSold[symbol] = False
elif self.overBought[symbol] and bbPercentBandwidth < self.shortEntry: # SHORT entry
self.orders[symbol] = self.MarketOrder(symbol, -qty, False, f'ENTER short {bbVal}')
self.overBought[symbol] = False
else:
isLong = self.Portfolio[symbol].IsLong
isShort = self.Portfolio[symbol].IsShort
entryPrice = self.orders[symbol].AverageFillPrice
currentPrice = data[symbol].Close
if isLong and bbPercentBandwidth > self.longExit:
self.Liquidate(symbol, f'EXIT long {bbVal}')
elif isShort and bbPercentBandwidth < self.shortExit:
self.Liquidate(symbol, f'EXIT short {bbVal}')