| Overall Statistics |
|
Total Trades 63 Average Win 1.53% Average Loss -0.83% Compounding Annual Return -35.695% Drawdown 10.500% Expectancy -0.358 Net Profit -9.187% Sharpe Ratio -1.686 Probabilistic Sharpe Ratio 6.524% Loss Rate 77% Win Rate 23% Profit-Loss Ratio 1.84 Alpha -0.277 Beta 0.011 Annual Standard Deviation 0.163 Annual Variance 0.027 Information Ratio -2.178 Tracking Error 0.208 Treynor Ratio -25.246 Total Fees $0.00 |
import decimal as d
from System.Drawing import Color
class MovingAverageBasic(QCAlgorithm):
#optimum atr SL for AUD is 5x ATR
def Initialize(self):
self.SetStartDate(2014,12,10) # Set Start Date
self.SetEndDate(2015,2,27)
self.SetCash(1000000) # Set Strategy Cash
self.defaultQuantity = 100000
#self.AddForex("AUDUSD", Resolution.Hour, Market.Oanda) #AddForex merely adds the security, but you cant refer to it later.
self.audusd = self.AddForex("AUDUSD", Resolution.Hour, Market.Oanda).Symbol #But doing this you now can refer to self.symbol
# Symbols are a way to identify an asset uniquely. They are objects which contain all the information required
# to identify a security, without needing external references, or proprietary database look-ups.
self.SetBrokerageModel(BrokerageName.OandaBrokerage)
self.fastEMA = self.EMA("AUDUSD", 10, Resolution.Hour)
self.slowEMA = self.EMA("AUDUSD", 100, Resolution.Hour)
self.BollinBand = self.BB("AUDUSD",20,2,MovingAverageType.Simple, Resolution.Hour)
self.fastEMAWin = RollingWindow[float](10)
self.slowEMAWin = RollingWindow[float](10)
self.PriceWin = RollingWindow[float](3)
self.OrderIDWindow = RollingWindow[float](2)
self.ATRindy = self.ATR("AUDUSD",20,MovingAverageType.Simple, Resolution.Hour)
self.SetWarmUp(100)
self.fill_price = 0
self.quant_filled = 0
#Risk Management
self.leverage = self.Securities["AUDUSD"].Leverage
self.pip = self.Securities["AUDUSD"].SymbolProperties.MinimumPriceVariation * 10 #times 10 converts pipette to pip
#initializing charts
#Chart.Stacked: This means the chart will appear as a separate chart below the main equity chart.
#Chart.Overlay: This means that the chart will be overlayed on top of the main equity chart.
FXPlot = Chart("FX Plot", ChartType.Stacked)
# On the Trade Plotter Chart we want 3 series: trades and price:
FXPlot.AddSeries(Series("Price", SeriesType.Line, 0))
FXPlot.AddSeries(Series("Buy", SeriesType.Scatter, '$', Color.Green, ScatterMarkerSymbol.Triangle))
FXPlot.AddSeries(Series("Sell", SeriesType.Scatter, '$', Color.Red, ScatterMarkerSymbol.TriangleDown))
FXPlot.AddSeries(Series("FastMA", SeriesType.Line, '$' , Color.Orange))
FXPlot.AddSeries(Series("SlowMA", SeriesType.Line, '$', Color.Purple))
FXPlot.AddSeries(Series("BBUp",SeriesType.Line, '$'))
FXPlot.AddSeries(Series("BBMid",SeriesType.Line, '$'))
FXPlot.AddSeries(Series("BBLow",SeriesType.Line, '$'))
ATRnBB = Chart("Indicators 2", ChartType.Overlay)
#self.Plot("BB", "MiddleBand", self.bb.MiddleBand.Current.Value)
#self.Plot("BB", "UpperBand", self.bb.UpperBand.Current.Value)
#self.Plot("BB", "LowerBand", self.bb.LowerBand.Current.Value)
self.AddChart(FXPlot)
def OnData(self, data):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
Arguments:
data: Slice object keyed by symbol containing the stock data
'''
# Creates an indicator and adds to a rolling window when it is updated
self.fastEMAWin.Add(self.fastEMA.Current.Value)
self.slowEMAWin.Add(self.slowEMA.Current.Value)
self.ATR_Now = self.ATRindy.Current.Value
if not self.slowEMA.IsReady:
return
if not self.fastEMA.IsReady:
return
if self.IsWarmingUp:
return
self.TradeSize = self.CalculateTradeSize()
#Logging-------------------------------------------------------------------------------
Cutup = self.CrossAbove(self.fastEMAWin, self.slowEMAWin)
Cutdown = self.CrossBelow(self.fastEMAWin, self.slowEMAWin)
time_now = self.Time
holdings = self.Securities["AUDUSD"].Holdings.Quantity
if self.Portfolio[self.audusd].IsLong:
if self.Falling(self.slowEMAWin, self.slowEMAWin):
self.Liquidate(self.audusd)
self.Log("Closing Long | Cutup is {} | Cutdown is {}".format(Cutup, Cutdown))
self.ClosePrice = self.fill_price
self.Log("Opened at {} and closed at {}".format(self.OpenPrice,self.ClosePrice))
elif self.Portfolio[self.audusd].IsShort:
if self.Rising(self.slowEMAWin, self.slowEMAWin):
self.Liquidate(self.audusd)
self.Log("Closing Short | Cutup is {} | Cutdown is {}".format(Cutup, Cutdown))
self.ClosePrice = self.fill_price
self.Log("Opened at {} and closed at {}".format(self.OpenPrice,self.ClosePrice))
else:
if self.CrossAbove(self.fastEMAWin, self.slowEMAWin) and not self.Falling(self.slowEMAWin, self.slowEMAWin):
self.MarketOrder(self.audusd, self.TradeSize)
self.Log("New Long | Cutup is {} | Cutdown is {}".format(Cutup, Cutdown))
#self.Log("Market long order fill price is {}".format(self.fill_price))
#insert calculation function here
self.StopMarketOrder(self.audusd, -self.TradeSize, self.fill_price - 5*self.ATR_Now )
self.OpenPrice = self.fill_price
self.Log("New Opened at {}".format(self.OpenPrice))
#self.holdings = self.Securities["AUDUSD"].Holdings.Quantity
if self.CrossBelow(self.fastEMAWin, self.slowEMAWin) and not self.Rising(self.slowEMAWin, self.slowEMAWin):
self.MarketOrder(self.audusd, -self.TradeSize)
self.Log("New Short | Cutup is {} | Cutdown is {}".format(Cutup, Cutdown))
#self.Log("Market short order fill price is {}".format(self.fill_price))
#insert calculation function here
self.StopMarketOrder(self.audusd, self.TradeSize, self.fill_price +5*self.ATR_Now )
self.OpenPrice = self.fill_price
self.Log("New Opened at {}".format(self.OpenPrice))
#self.holdings = self.Securities["AUDUSD"].Holdings.Quantity
#below is all for the charting
self.Plot("FX Plot", "FastMA", self.fastEMA.Current.Value)
self.Plot("FX Plot", "SlowMA", self.slowEMA.Current.Value)
self.Plot("FX Plot","Price", data["AUDUSD"].Price)
self.Plot("FX Plot", "BBUp", self.BollinBand.UpperBand.Current.Value)
self.Plot("FX Plot", "BBMid",self.BollinBand.MiddleBand.Current.Value)
self.Plot("FX Plot", "BBLow",self.BollinBand.LowerBand.Current.Value)
self.Plot("Indicators 2", "ATR", self.ATRindy.Current.Value)
self.Plot("Indicators 2", "BB Range", (self.BollinBand.UpperBand.Current.Value - self.BollinBand.LowerBand.Current.Value))
#below are event handlers, as well as functions to determine the status of the EMA
#-------------------------------------------------------------------------------
def CrossAbove(self, fast, slow, tolerance=0):
return fast[0] > slow[0] * (1 + tolerance) and fast[2] < slow[2] * (1 - tolerance)
def CrossBelow(self, fast, slow, tolerance = 0):
return fast[0] < slow[0] * (1 - tolerance) and fast[2] > slow[2] * (1 + tolerance)
def Rising(self, current, lookback, tolerance = 0):
return current[0] > lookback[2] * (1 + tolerance)
def Falling(self, current, lookback, tolerance = 0):
return current[0] < lookback[2] * (1 - tolerance)
def CalculateTradeSize(self):
self.MaxLossAbsolute = self.Portfolio.Cash * 0.01
return self.MaxLossAbsolute / (2 * self.ATR_Now)
def OnOrderEvent(self, orderEvent):
self.order_tick = self.Transactions.GetOrderById(orderEvent.OrderId)
self.OrderIDWindow.Add(self.Transactions.LastOrderId)
self.fill_price = orderEvent.FillPrice
self.quant_filled = orderEvent.FillQuantity
if self.fill_price > 0:
if self.quant_filled > 0:
self.Plot("FX Plot","Buy",self.fill_price)
elif self.quant_filled <0:
self.Plot("FX Plot","Sell",self.fill_price)
#self.Log("An order was filled at {}".format(self.fill_price))
if (self.OrderIDWindow.IsReady == True) and (self.Portfolio[self.audusd].IsLong == False) and (self.Portfolio[self.audusd].IsShort == False):
self.Log("Closing Order ID is: {} and Opening order ID is {}".format(self.OrderIDWindow[0], self.OrderIDWindow[1] ))
return self.fill_price