| Overall Statistics |
|
Total Trades 2226 Average Win 0.61% Average Loss -0.08% Compounding Annual Return -96.208% Drawdown 55.600% Expectancy -0.890 Net Profit -54.056% Sharpe Ratio -3.64 Probabilistic Sharpe Ratio 0.000% Loss Rate 99% Win Rate 1% Profit-Loss Ratio 7.78 Alpha -0.895 Beta 0 Annual Standard Deviation 0.246 Annual Variance 0.06 Information Ratio -3.922 Tracking Error 0.273 Treynor Ratio -11613.066 Total Fees $4116.25 Estimated Strategy Capacity $430000.00 Lowest Capacity Asset GC XUQKQ0O7BY59 |
class Fractals:
def __init__(self, context):
self.context = context
def BullishCalculations(self):
#FRACTAL FOR BULLISH ENTRY AND HIGHER HIGH CALC
if (self.context.quickTradeBarWindow[3].Low > self.context.quickTradeBarWindow[1].Low < self.context.quickTradeBarWindow[2].Low) and (self.context.quickTradeBarWindow[0].Low > self.context.quickTradeBarWindow[1].Low):
self.OneUp = True
else:
self.OneUp = False
if (self.context.quickTradeBarWindow[4].High < self.context.quickTradeBarWindow[2].High > self.context.quickTradeBarWindow[3].High) and (self.context.quickTradeBarWindow[1].High < self.context.quickTradeBarWindow[2].High > self.context.quickTradeBarWindow[0].High):
self.OneDown = True
else:
self.OneDown = False
if self.OneUp is True:
self.context.bullOne = 1
else:
self.context.bullOne = 0
if self.OneDown is True:
self.context.bearOne = -1
else:
self.context.bearOne = 0
return self.context.bearOne
def BearishCalculations(self):
if (self.context.quickTradeBarWindow[4].Low > self.context.quickTradeBarWindow[2].Low < self.context.quickTradeBarWindow[3].Low) and (self.context.quickTradeBarWindow[1].Low > self.context.quickTradeBarWindow[2].Low < self.context.quickTradeBarWindow[0].Low):
self.OneUpBear = True
else:
self.OneUpBear = False
if (self.context.quickTradeBarWindow[3].High < self.context.quickTradeBarWindow[1].High > self.context.quickTradeBarWindow[2].High) and (self.context.quickTradeBarWindow[0].High < self.context.quickTradeBarWindow[1].High):
self.OneDownBear = True
else:
self.OneDownBear = False
if self.OneUpBear is True:
self.context.bullOneRed = 1
else:
self.context.bullOneRed = 0
if self.OneDownBear is True:
self.context.bearOneRed = -1
else:
self.context.bearOneRed = 0
return self.context.bearOneRed
# Your New Python Fileclass ConsolidatedFractals:
def __init__(self, context):
self.context = context
def UpFractalFormula(self):
if (self.context.longTradeBarWindow[4].Low > self.context.longTradeBarWindow[2].Low < self.context.longTradeBarWindow[3].Low) and (self.context.longTradeBarWindow[1].Low > self.context.longTradeBarWindow[2].Low < self.context.longTradeBarWindow[0].Low):
return True
else:
return False
def DownFractalFormula(self):
if (self.context.longTradeBarWindow[4].High < self.context.longTradeBarWindow[2].High > self.context.longTradeBarWindow[3].High) and (self.context.longTradeBarWindow[1].High < self.context.longTradeBarWindow[2].High > self.context.longTradeBarWindow[0].High):
return True
else:
return False
def SetSupport(self, fiveUp):
self.bullFive = 1 if fiveUp is True else 0
if self.bullFive == 1:
self.support = self.context.longTradeBarWindow[2].Low
self.context.breakdown = False
self.context.first_position_bear = False
self.context.second_position_bear = False
#Resets the losing_outcome becuase there's a new thesis
self.context.bear_losing_outcome = False
return self.support
else:
return self.context.support
def SetResistance(self, fiveDown):
self.bearFive = -1 if fiveDown is True else 0
if self.bearFive == -1:
self.resistance = self.context.longTradeBarWindow[2].High
self.context.breakout = False
self.context.first_position_bull = False
self.context.second_position_bull = False
#Reset the losing_outcome becuase there's a new thesis
self.context.bull_losing_outcome = False
return self.resistance
else:
return self.context.resistance
# Your New Python Fileclass FiveOneFractalBreakoutCopy(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2021, 9, 15) # Set Start Date
self.SetCash(100000) # Set Strategy Cash
from future_set_up import FutureSetUp
newFutureSetUp = FutureSetUp(self)
self.SetSecurityInitializer(newFutureSetUp.OpenInterestSecurityInitializer)
gc = self.AddFuture(Futures.Metals.Gold, Resolution.Minute)
gc.SetFilter(lambda x: x.FrontMonth().OnlyApplyFilterAtMarketOpen())
# VARIABLES & LIST
self.rules = []
self.bearFive = None
self.bullFive = None
self.bullOne = None
self.bearOne = None
self.FiveUp = None
self.FiveDown = None
self.first_low = None
self.second_low = None
self.first_high = None
self.second_high = None
#Used to check if the first trade in a thesis was a loser.
self.bull_losing_outcome = False
self.bear_losing_outcome = False
#A set of variables used to limit re-entries to only happen once per thesis
self.first_position_bull = None
self.second_position_bull = None
self.first_position_bear = None
self.second_position_bear = None
#Used for making sure re-entries happen on a new fractal
self.entry_minute = None
#DIRECTION VARIABLES
self.support = None
self.resistance = None
self.breakout = None
self.breakdown = None
#HISTORY WINDOWS FOR 5M & 1M
self.quickTradeBarWindow = RollingWindow[QuoteBar](5)
self.longTradeBarWindow = RollingWindow[TradeBar](5)
#FIVE MINUTE BARS
self.Consolidate(gc.Symbol, timedelta(minutes=5), self.OnDataConsolidated)
# ORDER VARIABLES
self.short_stop = None
self.second_short_stop = None
self.long_stop = None
self.second_long_stop = None
self.long_entry = None
self.second_long_entry = None
self.short_entry = None
self.second_short_entry = None
self.long_exit = None
self.second_long_exit = None
self.short_exit = None
self.second_short_exit = None
self.openOrders = self.Transactions.GetOpenOrders()
self.longOrders = []
self.shortOrders = []
self.partial_exit_fill_safety_long = None
self.partial_fill_liq_price = None
self.partial_exit_fill_safety_short = None
self.partial_fill_liq_price = None
self.risk_target = None
self.buying_power = None
self.share_size = None
self.dollar_size = None
self.liquidContract = None
self.liquidContractFive = None
def OnDataConsolidated(self, bar):
#5M DATA SETUP
self.liquidContract = self.liquidContractFive
if self.liquidContract is None:
return
self.bar = bar
self.longTradeBarWindow.Add(self.bar)
if not self.longTradeBarWindow.IsReady:
return
from consolidated_fractals import ConsolidatedFractals
newConsolidatedFractals = ConsolidatedFractals(self)
#5M UP-FRACTAL FORMULA
self.FiveUp = newConsolidatedFractals.UpFractalFormula()
#5M DN-FRACTAL FORMULA
self.FiveDown = newConsolidatedFractals.DownFractalFormula()
#SET SUPPORT, RESET NON-DIRECTIONAL STATUS
self.support = newConsolidatedFractals.SetSupport(self.FiveUp)
#SET RESISTANCE, RESET NON-DIRECTIONAL STATUS
self.resistance = newConsolidatedFractals.SetResistance(self.FiveDown)
if self.support is None:
return
if self.resistance is None:
return
if self.partial_exit_fill_safety_long is True and self.Securities[self.liquidContract].Low <= self.partial_fill_liq_price:
self.Liquidate(self.liquidContract)
self.partial_exit_fill_safety_long = False
self.partial_fill_liq_price = None
if self.partial_exit_fill_safety_short is True and self.Securities[self.liquidContract].Low >= self.partial_fill_liq_price:
self.Liquidate(self.liquidContract)
self.partial_exit_fill_safety_short = False
self.partial_fill_liq_price = None
#SET BULLISH DIRECTIONAL STATUS
if self.Securities[self.liquidContract].Close > self.resistance:
self.breakout = True
#SET BEARISH DIRECTIONAL STATUS
if self.Securities[self.liquidContract].Close < self.support:
self.breakdown = True
def OnData(self, slice):
from future_set_up import FutureSetUp
from quick_window import QuickWindow
from fractals import Fractals
#Set Contract
newFutureSetUp = FutureSetUp(self)
liquidContract = newFutureSetUp.SetContract(slice)
if(liquidContract == None):
return
#UPDATE QUICK WINDOW
newQuickWindow = QuickWindow(self)
isReady = newQuickWindow.UpdateQuickWindow(slice)
if(not isReady):
return
#LIQUIDATES POSITIONS IN THE EVENT OF A DOUBLE-FILL
if self.openOrders is [] and self.Portfolio.Invested:
self.Liquidate(self.liquidContract)
newFractal = Fractals(self)
#FRACTAL FOR BULLISH ENTRY AND HIGHER HIGH CALC
self.bearOne = newFractal.BullishCalculations()
#FRACTAL FOR BEARISH ENTRY AND LOWER LOW CALC
self.bearOneRed = newFractal.BearishCalculations()
#HIGHER HIGHS...
if self.bearOne == -1 and self.first_high is None:
self.first_high = self.quickTradeBarWindow[2].High
#If we have the first high but not the second...
elif self.bearOne == -1 and self.first_high is not None and self.second_high is None:
self.second_high = self.quickTradeBarWindow[2].High
#If we have the first two highs and there's a new fractal...
elif self.bearOne == -1 and self.first_high is not None and self.second_high is not None:
self.pass_v = self.second_high
self.second_high = self.quickTradeBarWindow[2].High
self.first_high = self.pass_v
#if values are all empty, return...
if self.second_high is None or self.first_high is None:
return
#If highers highs...
if self.second_high >= self.first_high and "Highs" not in self.rules:
self.rules.append("Highs")
elif self.second_high < self.first_high and "Highs" in self.rules:
self.rules.remove("Highs")
#LOWER LOWS...
if self.bullOneRed == 1 and self.first_low is None:
self.first_low = self.quickTradeBarWindow[2].Low
#If we have the first high but not the second...
elif self.bullOneRed == 1 and self.first_low is not None and self.second_low is None:
self.second_low = self.quickTradeBarWindow[2].Low
#If we have the first two highs and there's a new fractal...
elif self.bullOneRed == 1 and self.first_low is not None and self.second_low is not None:
self.pass_v = self.second_low
self.second_low = self.quickTradeBarWindow[2].Low
self.first_low = self.pass_v
#if values are all empty, return...
if self.second_low is None or self.first_low is None:
return
#If lower lows...
if self.second_low <= self.first_low and "Lows" not in self.rules:
self.rules.append("Lows")
#Remove lows if they are higher
elif self.second_low > self.first_low and "Lows" in self.rules:
self.rules.remove("Lows")
invested = self.Portfolio.Invested
close_price = self.quickTradeBarWindow[0].Close
self.Debug("RULES: " + str(self.rules))
self.Debug("BREAKDOWN: " + str(self.breakdown))
self.Debug("BREAKOUT: " + str(self.breakout))
self.Debug("BULL FRACTAL: " + str(self.bullOne))
self.Debug("BEAR FRACTAL: " + str(self.bearOneRed))
self.Debug("BREAKDOWN: " + str(self.breakdown))
self.Debug("SUPPORT: " + str(self.support))
self.Debug("RESISTANCE: " + str(self.resistance))
self.Debug("INVESTED: " + str(invested))
self.Debug("CLOSE PRICE: " + str(close_price))
#BEARISH EXECUTION LOGIC = 5M CLOSING BREAK, NOT HOLDING, 1M FRACTAL, ENTRY PRICE < SUPPORT
if self.breakdown is True and not self.Portfolio.Invested and self.bearOneRed == -1 and self.quickTradeBarWindow[0].Close < self.support and "Lows" in self.rules and self.second_position_bear is False:
self.Debug("BEAR IF EXECUTION MET")
#ENTRY AT THE CLOSE OF THE CANDLE FOLLOWING THE FRACTAL
self.entry_price = self.quickTradeBarWindow[0].Close
#STOP ONE TICK ABOVE THE HIGHEST FRACTAL POINT
self.stop_price = self.quickTradeBarWindow[1].High + 0.01
#TICK DISTANCE FOR EXIT
self.pass_value = (self.stop_price - self.entry_price) * 2
#2:1 EXIT PRICE
self.exit_price = self.entry_price - self.pass_value
#AVAILABLE CAPITAL
self.buying_power = self.Portfolio.Cash
#DOLLAR RISK TARGET (0.25%)
self.risk_target = self.buying_power / 400
#ENTRY-STOP DOLLAR DISTANCE
self.risk_per_share = self.pass_value / 2
#IDEAL SHARE SIZE (avaiable capital not considered)
self.share_size = self.risk_target / self.risk_per_share
#PRICE OF IDEAL SIZE
self.dollar_size = self.share_size * self.entry_price
#COMPARES IDEAL SIZE WITH CAPITAL
if self.dollar_size > self.buying_power:
#NEW SHARE SIZE
self.share_size = self.buying_power / self.entry_price
#TEMP CONDITION THAT REDUCES MASSIVE TRADES
if self.entry_price > self.second_low and self.first_position_bear is False:
self.Debug("LAST BEAR CONDITION")
#SHORT
self.short_entry = self.LimitOrder(self.liquidContract, -1, self.entry_price)
#CUT LOSSES
self.short_stop = self.StopMarketOrder(self.liquidContract, 1, self.stop_price)
#TAKE PROFIT
self.short_exit = self.LimitOrder(self.liquidContract, 1, self.exit_price)
#STORES ORDER TICKETS IN A LIST
self.shortOrders = [self.short_entry, self.short_stop, self.short_exit]
#STORES FIRST TRADE AS HAVING HAPPENED
self.first_position_bear = True
#LOGS TIME ORDERS WERE PLACED
self.entry_minute = self.Time.minute
if self.entry_price > self.second_low and self.first_position_bear is True and self.second_position_bear is False and self.Time.minute > self.entry_minute or self.Time.minute == 0 and self.entry_minute != 0 and self.bear_losing_outcome is True:
self.Debug("LAST BEAR CONDITION")
#SHORT
self.second_short_entry = self.LimitOrder(self.liquidContract, -1, self.entry_price)
#CUT LOSSES
self.second_short_stop = self.StopMarketOrder(self.liquidContract, 1, self.stop_price)
#TAKE PROFIT
self.second_short_exit = self.LimitOrder(self.liquidContract, 1, self.exit_price)
#STORES ORDER TICKETS IN A LIST
self.shortOrders = [self.second_short_entry, self.second_short_stop, self.second_short_exit]
#STORES SECOND POSITION
self.second_position_bear = True
#BREAKOUT EXECUTION (NEED TO ADD PRICE CONDITION)
if self.breakout is True and not self.Portfolio.Invested and self.bullOne == 1 and self.quickTradeBarWindow[0].Close > self.resistance and "Highs" in self.rules and self.second_position_bull is False:
self.Debug("BULL IF EXECUTION MET")
#ENTRY AT THE CLOSE OF THE CANDLE FOLLOWING THE FRACTAL
self.entry_price = self.quickTradeBarWindow[0].Close
#STOP ONE TICK BELOW THE LOWEST FRACTAL POINT
self.stop_price = self.quickTradeBarWindow[1].Low - 0.01
#TICK DISTANCE FOR EXIT
self.pass_value = (self.entry_price - self.stop_price) * 2
#2:1 EXIT PRICE
self.exit_price = (self.pass_value + self.quickTradeBarWindow[0].Close)
#AVAILABLE CAPITAL
self.buying_power = self.Portfolio.Cash
#DOLLAR RISK TARGET (0.25%)
self.risk_target = self.buying_power / 400
#ENTRY-STOP DOLLAR DISTANCE
self.risk_per_share = self.pass_value / 2
#IDEAL SHARE SIZE (avaiable capital not considered)
self.share_size = self.risk_target / self.risk_per_share
#PRICE OF IDEAL SIZE
self.dollar_size = self.share_size * self.entry_price
#COMPARES IDEAL SIZE WITH CAPITAL
if self.dollar_size > self.buying_power:
#NEW SHARE SIZE
self.share_size = self.buying_power / self.entry_price
#TEMP CONDITION THAT REDUCES MASSIVE TRADES
if self.entry_price < self.second_high and self.first_position_bull is False:
self.Debug("LAST BULL CONDITION")
self.long_entry = self.LimitOrder(self.liquidContract, 1, self.entry_price)
self.long_stop = self.StopMarketOrder(self.liquidContract, -1, self.stop_price)
self.long_exit = self.LimitOrder(self.liquidContract, -1, self.exit_price)
self.longOrders = [self.long_entry, self.long_stop, self.long_exit]
self.first_position_bull = True
self.entry_minute = self.Time.minute
if self.entry_price < self.second_high and self.first_position_bull is True and self.second_position_bull is False and self.Time.minute > self.entry_minute or self.Time.minute == 0 and self.entry_minute != 0 and self.bull_losing_outcome is True:
self.Debug("LAST BULL CONDITION")
self.second_long_entry = self.LimitOrder(self.liquidContract, 1, self.entry_price)
self.second_long_stop = self.StopMarketOrder(self.liquidContract, -1, self.stop_price)
self.second_long_exit = self.LimitOrder(self.liquidContract, -1, self.exit_price)
self.longOrders = [self.second_long_entry, self.second_long_stop, self.second_long_exit]
self.second_position_bull = True
def OnOrderEvent (self, orderEvent):
#CLOSES ALL IF LONG ENTRY NOT FILLED AND EXIT REACHED
if self.longOrders is not None:
if orderEvent.Status == OrderStatus.Submitted and not self.Portfolio.Invested and orderEvent.OrderId in self.longOrders and self.Securities[self.liquidContract].High >= self.exit_price:
self.Transactions.CancelOpenOrders(self.liquidContract)
self.Liquidate(self.liquidContract)
#CLOSES ALL IF SHORT ENTRY NOT FILLED AND EXIT REACHED
if self.shortOrders is not None:
if orderEvent.Status == OrderStatus.Submitted and not self.Portfolio.Invested and orderEvent.OrderId in self.shortOrders and self.Securities[self.liquidContract].Low <= self.exit_price:
self.Transactions.CancelOpenOrders(self.liquidContract)
self.Liquidate(self.liquidContract)
#CLOSES ALL IF AN ORDER IS FILLED AND WE'RE NOT INVESTED
if orderEvent.Status == OrderStatus.Filled and not self.Portfolio.Invested:
self.Transactions.CancelOpenOrders(self.liquidContract)
self.Liquidate(self.liquidContract)
#CLOSES ALL IF BUY STOP IS FILLED
if self.short_stop is not None:
if orderEvent.Status == OrderStatus.Filled and orderEvent.OrderId == self.short_stop:
self.Transactions.CancelOpenOrders(self.liquidContract)
self.Liquidate(self.liquidContract)
#CLOSES ALL IF SELL STOP IS FILLED
if self.long_stop is not None:
if orderEvent.Status == OrderStatus.Filled and orderEvent.OrderId == self.long_stop:
self.Transactions.CancelOpenOrders(self.liquidContract)
self.Liquidate(self.liquidContract)
#CLOSES ALL IF BUY LIMIT IS FILLED FOR SHORT POSITION
if self.short_exit is not None:
if orderEvent.Status == OrderStatus.Filled and orderEvent.OrderId == self.short_exit:
self.Transactions.CancelOpenOrders(self.liquidContract)
self.Liquidate(self.liquidContract)
#CLOSES ALL IF SELL LIMIT IS FILLED FOR LONG POSITION
if orderEvent.Status == OrderStatus.Filled and orderEvent.OrderId == self.short_exit:
self.Transactions.CancelOpenOrders(self.liquidContract)
self.Liquidate(self.liquidContract)
#If the first bullish trade was a LOSS, set the value of bull_losing_outcome to True
if orderEvent.OrderId == self.long_stop and orderEvent.Status == OrderStatus.Filled:
self.bull_losing_outcome = True
#If the first bearish trade was a LOSS, set the value of bear_losing_outcome to True
if orderEvent.OrderId == self.short_stop and orderEvent.Status == OrderStatus.Filled:
self.bear_losing_outcome = True
#Partial-Filled Exit Safety Measures, far from ideal, still doesn't account for entry partial fills.
if orderEvent.OrderId == self.long_exit and orderEvent.OrderStatus == OrderStatus.PartiallyFilled:
self.long_stop.Cancel
self.partial_exit_fill_safety_long = True
elif orderEvent.OrderId == self.long_exit and orderEvent.OrderStatus == OrderStatus.Filled:
self.partial_exit_fill_safety_long = False
if orderEvent.OrderId == self.second_long_exit and orderEvent.OrderStatus == OrderStatus.PartiallyFilled:
self.second_long_stop.Cancel
self.partial_exit_fill_safety_long = True
elif orderEvent.OrderId == self.second_long_exit and orderEvent.OrderStatus == OrderStatus.Filled:
self.partial_exit_fill_safety_long = False
if orderEvent.OrderId == self.short_exit and orderEvent.OrderStatus == OrderStatus.PartiallyFilled:
self.short_stop.Cancel
self.partial_exit_fill_safety_short = True
elif orderEvent.OrderId == self.short_exit and orderEvent.OrderStatus == OrderStatus.PartiallyFilled:
self.partial_exit_fill_safety_short = False
if orderEvent.OrderId == self.second_short_exit and orderEvent.OrderStatus == OrderStatus.PartiallyFilled:
self.second_short_stop.Cancel
self.partial_exit_fill_safety_short = True
elif orderEvent.OrderId == self.second_short_exit and orderEvent.OrderStatus == OrderStatus.PartiallyFilled:
self.partial_exit_fill_safety_short = Falseclass FutureSetUp:
def __init__(self, context):
self.context = context
def OpenInterestSecurityInitializer(self, security):
if security.Type == SecurityType.Future:
history = self.context.History([security.Symbol], timedelta(1))
if 'openinterest' in history:
oi = OpenInterest(self.context.Time, security.Symbol,
history.openinterest.dropna().iloc[-1])
security.SetMarketPrice(oi)
def GrabFrontMonthContract(self, slice):
liquidContract = None
for chain in slice.FutureChains:
chainValue = chain.Value
contracts = chainValue.Contracts
for contract in contracts.Values:
liquidContract = contract
if liquidContract == None:
return None
else:
return liquidContract
def SetContract(self, slice):
liquidContract = self.GrabFrontMonthContract(slice)
if (liquidContract == None):
return None
self.context.liquidContractFive = liquidContract.Symbol
if (self.context.liquidContract == None):
self.context.liquidContract = self.context.liquidContractFive
return liquidContract
# Your New Python Fileclass QuickWindow:
def __init__(self, context):
self.context = context
def UpdateQuickWindow(self, slice):
if slice.ContainsKey(self.context.liquidContract):
self.context.quickTradeBarWindow.Add(self.context.CurrentSlice[self.context.liquidContract])
if not self.context.quickTradeBarWindow.IsReady:
return False
#SETS TRADING HOURS AND EOD LIQUIDATION
#if self.Time.hour < 6:
# return
#if self.Time.hour > 16:
# return
if self.context.Time.hour == 15 and self.context.Time.minute == 59:
self.context.Liquidate(self.context.liquidContract)
return True
# Your New Python File