| Overall Statistics |
|
Total Trades 25 Average Win 1.10% Average Loss -4.80% Compounding Annual Return 3.784% Drawdown 6.500% Expectancy 0.127 Net Profit 7.392% Sharpe Ratio 0.559 Probabilistic Sharpe Ratio 24.449% Loss Rate 8% Win Rate 92% Profit-Loss Ratio 0.23 Alpha 0.013 Beta 0.096 Annual Standard Deviation 0.058 Annual Variance 0.003 Information Ratio -0.776 Tracking Error 0.214 Treynor Ratio 0.337 Total Fees $0.00 Estimated Strategy Capacity $120000.00 Lowest Capacity Asset USDCAD 8G |
from datetime import datetime,timedelta
import numpy as np
#from dailyhours import *
#from fourhr_support_resistance import *
Macdlong = None
class MeasuredApricot(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2019, 1, 30) # Set Start Date
self.SetEndDate(2020, 12, 30)
self.SetCash(100000) # Set Strategy Cash
self.ticker = "USDCAD"
# Rolling Windows to hold bar close data keyed by symbol
self.Data = {}
#for ticker in tickers:
symbol = self.AddForex(self.ticker, Resolution.Hour, Market.Oanda).Symbol
self.Data[symbol] = SymbolData(self, symbol)
self.tolerance = 0.0025
self.stopLossLevel = -0.05 # stop loss percentage
self.stopProfitLevel = 0.01# stop profit percentage
#self.SupportResistance = SupportResistance(self, self.ticker)
self.SetWarmUp(50, Resolution.Hour)
#def MarketClose(self):
#self.SupportResistance.Reset()
def OnData(self, data):
if self.IsWarmingUp: #Data to warm up the algo is being collected.
return
for symbol, symbolData in self.Data.items(): #Return the dictionary's key-value pairs:
if not (data.ContainsKey(symbol) and data[symbol] is not None and symbolData.IsReady):
continue
MACD = symbolData.macd.Current.Value
MACDfast = symbolData.macd.Fast.Current.Value
RSI = symbolData.rsi.Current.Value
current_price = data[symbol].Close
signalDeltaPercent = (MACD - MACD)/MACDfast
#nextSupportZone =
#nextResistanceZone =
#support = self.SupportResistance.NextSupport()
#resistance = self.SupportResistance.NextResistance()
if self.Portfolio[symbol].Invested:
if self.isLong:
condStopProfit = (current_price - self.buyInPrice)/self.buyInPrice > self.stopProfitLevel
condStopLoss = (current_price - self.buyInPrice)/self.buyInPrice < self.stopLossLevel
if condStopProfit:
self.Liquidate(symbol)
self.Log(f"{self.Time} Long Position Stop Profit at {current_price}")
if condStopLoss:
self.Liquidate(symbol)
self.Log(f"{self.Time} Long Position Stop Loss at {current_price}")
else:
condStopProfit = (self.sellInPrice - current_price)/self.sellInPrice > self.stopProfitLevel
condStopLoss = (self.sellInPrice - current_price)/self.sellInPrice < self.stopLossLevel
if condStopProfit:
self.Liquidate(symbol)
self.Log(f"{self.Time} Short Position Stop Profit at {current_price}")
if condStopLoss:
self.Liquidate(symbol)
self.Log(f"{self.Time} Short Position Stop Loss at {current_price}")
if not self.Portfolio[symbol].Invested:
MacdLong = signalDeltaPercent > self.tolerance
#Above Support = current_price > closestSupportZone * tolerance(1.01)
#Below Resistance = current_price < closestResistanceZone * tolerance
# tolerance = will be dependent on the minimum number of pips before a r/s level
if RSI > 50 and Macdlong: #Below Resistance:
self.SetHoldings(symbol, 1)
# get buy-in price for trailing stop loss/profit
self.buyInPrice = current_price
# entered long position
self.isLong = True
self.Log(f"{self.Time} Entered Long Position at {current_price}")
if RSI < 50 and not Macdlong: #Above Support:
self.SetHoldings(symbol, -1)
# get sell-in price for trailing stop loss/profit
self.sellInPrice = current_price
# entered short position
self.isLong = False
self.Log(f"{self.Time} Entered Short Position at {current_price}")
class SymbolData:
def __init__(self, algorithm, symbol):
self.macd = MovingAverageConvergenceDivergence(12,26,9)
self.rsi = RelativeStrengthIndex(14)
self.macdWindow = RollingWindow[IndicatorDataPoint](2) #setting the Rolling Window for the fast MACD indicator, takes two values
algorithm.RegisterIndicator(symbol, self.macd, timedelta(hours=4))
self.macd.Updated += self.MacdUpdated #Updating those two values
self.rsiWindow = RollingWindow[IndicatorDataPoint](2) #setting the Rolling Window for the slow SMA indicator, takes two values
algorithm.RegisterIndicator(symbol, self.rsi, timedelta(hours=4))
self.rsi.Updated += self.RsiUpdated #Updating those two values
self.closeWindow = RollingWindow[float](21)
# Add consolidator to track rolling close prices
self.consolidator = QuoteBarConsolidator(4)
self.consolidator.DataConsolidated += self.CloseUpdated
algorithm.SubscriptionManager.AddConsolidator(symbol, self.consolidator)
def MacdUpdated(self, sender, updated):
'''Event holder to update the MACD Rolling Window values'''
if self.macd.IsReady:
self.macdWindow.Add(updated)
def RsiUpdated(self, sender, updated):
'''Event holder to update the RSI Rolling Window values'''
if self.rsi.IsReady:
self.rsiWindow.Add(updated)
def CloseUpdated(self, sender, bar):
'''Event holder to update the close Rolling Window values'''
self.closeWindow.Add(bar.Close)
@property
def IsReady(self):
return self.macd.IsReady and self.rsi.IsReady and self.closeWindow.IsReady
from datetime import datetime,timedelta
SupportD = None
ResistanceD = None
class SupportResistance(ReversalAlpha):
def __init__(self, algorithm):
self.ticker = "USDCAD"
self.Algorithm = algorithm
self.SupportResistance = GetPriceLevels(self, series, variation = 0.005, h = 3)
#find out how to consolidate hourly data into 4hr bars
self.FourHourWindow = RollingWindow[float](7)
algorithm.Consolidate(self.Ticker, timedelta(hours=4), self.SaveFourHourBars)
def NextSupport(self):
price = self.Algorithm.Securities[self.Ticker].Price
SupportD, ResistanceD = self.SupportResistance
less_than_price = [x for x in SupportD if x < price ]
return less_than_price[min4(range(len(less_than_price)), key=lambda i: abs(less_than_price[i] - price))]
def NextResistance(self):
price = self.Algorithm.Securities[self.Ticker].Price
SupportD, ResistanceD = self.SupportResistance
greater_than_price = [y for y in ResistanceD if y > price ]
return greater_than_price[min(range(len(greater_than_price)), key=lambda i: abs(greater_than_price[i] - price))]
def SaveFourHourBars(self, bar):
self.FourHourWindow.Add(bar)
# Your New Python File
#How do you conduct an inheritance of methods of a class from another .py file and create a new method using data from
# the inherited class. .
#Here's a rough idea of what i wanted to create:
from datetime import datetime,timedelta
import numpy as np
class ReversalAlpha(QCAlgorithm):
def Initialize(self):
self.ticker = "USDCAD"
# Rolling Windows to hold bar close data keyed by symbol
self.closingData = {}
#for ticker in tickers:
symbol = self.AddForex(self.ticker, Resolution.Daily, Market.Oanda).Symbol
self.closingData[symbol] = RollingWindow[float](50)
# Warm up our rolling windows
self.SetWarmUp(50)
def OnData(self, data):
for symbol, window in self.closingData.items():
if data.ContainsKey(symbol) and data[symbol] is not None:
window.Add(data[symbol].Close)
if self.IsWarmingUp or not all([window.IsReady for window in self.closingData.values()]):
return
for symbol, window in self.closingData.items(): #references the key-value pairs in the dictionary
supports_D, resistances_D = self.GetPriceLevels(window) # Daily Supports and Daily Resistances
self.Log(f"Symbol: {symbol.Value} , Supports: {supports_D} , Resistances: {resistances_D}")
def GetPriceLevels(self, series, variation = 0.005, h = 3):
supports_D = [] # List that will hold daily Supports points
resistances_D = [] # List that will hold daily Resistances points
maxima = []
minima = []
# finding maxima and minima by looking for hills/troughs locally
for i in range(h, series.Size-h):
if series[i] > series[i-h] and series[i] > series[i+h]:
maxima.append(series[i])
elif series[i] < series[i-h] and series[i] < series[i+h]:
minima.append(series[i])
# identifying maximas which are resistances
for m in maxima:
r = m * variation
# maxima which are near each other
commonLevel = [x for x in maxima if x > m - r and x < m + r]
# if 2 or more maxima are clustered near an area, it is a resistance
if len(commonLevel) > 1:
# we pick the highest maxima if the cluster as our resistance
level = max(commonLevel)
if level not in resistances_D:
resistances_D.append(level)
# identify minima which are supports
for l in minima:
r = l * variation
# minima which are near each other
commonLevel = [x for x in minima if x > l - r and x < l + r]
# if 2 or more minima are clustered near an area, it is a support
if len(commonLevel) > 1:
# We pick the lowest minima of the cluster as our support
level = min(commonLevel)
if level not in supports_D:
supports_D.append(level)
return supports_D, resistances_D
# Your New Python File
#if nextSupportZone > current_price:
#return
from datetime import datetime,timedelta
SupportD = None
ResistanceD = None
class SupportResistance(ReversalAlpha):
def __init__(self, algorithm):
self.ticker = "USDCAD"
self.Algorithm = algorithm
self.SupportResistance = GetPriceLevels(self, series, variation = 0.005, h = 3)
#find out how to consolidate hourly data into 4hr bars
self.FourHourWindow = RollingWindow[float](21)
algorithm.Consolidate(self.Ticker, timedelta(hours=4), self.SaveFourHourBars)
def NextSupport(self):
price = self.Algorithm.Securities[self.Ticker].Price
SupportD, ResistanceD = self.SupportResistance
less_than_price = [x for x in SupportD if x < price ]
return less_than_price[min4(range(len(less_than_price)), key=lambda i: abs(less_than_price[i] - price))]
def NextResistance(self):
price = self.Algorithm.Securities[self.Ticker].Price
SupportD, ResistanceD = self.SupportResistance
greater_than_price = [y for y in ResistanceD if y > price ]
return greater_than_price[min(range(len(greater_than_price)), key=lambda i: abs(greater_than_price[i] - price))]
def SaveFourHourBars(self, bar):
self.FourHourWindow.Add(bar)
# Your New Python File
#How do you conduct an inheritance of methods of a class from another .py file and create a new method using data from
# the inherited class. .
#Here's a rough idea of what i wanted to create:
# Your New Python File