Overall Statistics |
Total Trades 922 Average Win 4.38% Average Loss -1.25% Compounding Annual Return 20.769% Drawdown 35.700% Expectancy 0.060 Net Profit 26.499% Sharpe Ratio 0.582 Probabilistic Sharpe Ratio 25.956% Loss Rate 77% Win Rate 23% Profit-Loss Ratio 3.51 Alpha 0.251 Beta 0.248 Annual Standard Deviation 0.409 Annual Variance 0.168 Information Ratio 0.672 Tracking Error 0.431 Treynor Ratio 0.959 Total Fees $0.00 Estimated Strategy Capacity $2700000.00 Lowest Capacity Asset EURUSD 8G Portfolio Turnover 665.63% |
# region imports from AlgorithmImports import * # endregion class SmoothRedDogfish(QCAlgorithm): def Initialize(self): self.SetStartDate(2022, 1, 1) # Set Start Date self.SetEndDate(2023, 3, 31) # Set End Date self.SetCash(1000) # Set Strategy Cash self.SetBenchmark("SPY") #self.symbol = self.AddEquity("AAPL", Resolution.Daily).Symbol #self.currency_pair = self.AddForex("EURUSD", Resolution.Minute, Market.Oanda).Symbol self.currencies = ["EURUSD", "GBPUSD"] self.Resolution = Resolution.Minute self.Data = {} self.BolingerData = {} self.SetBrokerageModel(BrokerageName.OandaBrokerage, AccountType.Margin) for symbol in self.currencies: self.currency = self.AddForex(symbol,self.Resolution, Market.Oanda, True, 30) self.Data[symbol] = self.currency # Consolidate bars self.consolidator = QuoteBarConsolidator(timedelta(minutes=30)) self.consolidator.DataConsolidated += self.consolidation_handler self.SubscriptionManager.AddConsolidator(symbol, self.consolidator) self.bollinger_bands = self.BB(symbol, 20, 2, MovingAverageType.Simple, self.Resolution) self.RegisterIndicator(symbol, self.bollinger_bands, timedelta(minutes=30)) self.BolingerData[symbol] = self.bollinger_bands # Schedule to trade between hour x and y # create on schedile method #self.Schedule.On(self.DateRules.EveryDay('GBPUSD'), self.TimeRules.At(6,0), Action(self._sessionOn)) #self.Schedule.On(self.DateRules.EveryDay('GBPUSD'), self.TimeRules.At(21,0), Action(self._sessionOff)) # Add end of day liquidation self.Schedule.On(self.DateRules.EveryDay('GBPUSD'), self.TimeRules.At(23, 58), Action(self.closePositionsEndOfDay)) # Add end of week liquidation self.Schedule.On(self.DateRules.Every(DayOfWeek.Friday), self.TimeRules.At(4, 58), Action(self.closePositionsEndOfWeek)) # Risk Management self.riskPercentage = 0.02 self.stopLossTarget = 40 # Profit target in pips self.profitTarget = 150 # Profit target in pip self.lotSize = 0.03 # Initilize order ticket self.CurrentOrderTicket = {symbol: None for symbol in self.currencies} self.StopLossTicket = {symbol: None for symbol in self.currencies} self.ProfitTargetTicket = {symbol: None for symbol in self.currencies} self.EURCurrentOrderTicket = None self.EURStopLossTicket = None self.EURProfitTargetTicket = None self.GBPCurrentOrderTicket = None self.GBPStopLossTicket = None self.GBPProfitTargetTicket = None # Add a chart self.chart = Chart('Price and Indicators ') self.chart.AddSeries(Series("Close",SeriesType.Line)) self.chart.AddSeries(Series("SMA",SeriesType.Line)) self.AddChart(self.chart) def _sessionOn(self): self._session = True def _sessionOff(self): self._session = False def consolidation_handler(self, sender: object, consolidated_bar: QuoteBar) -> None: #self.Log(f"{consolidated.Close} at {consolidated.EndTime}") if not self.bollinger_bands.IsReady: return # Execute trade for each pair for symbol in self.Data.keys(): invested = self.Portfolio[symbol].Invested if not invested: self.Debug(f'Symbol : {symbol}') # Forex example #mean = self.moving_average.Current.Value pip = self.Securities[symbol].SymbolProperties.MinimumPriceVariation current_price = self.Securities[symbol].Close accountBalance = self.Portfolio.CashBook["USD"].Amount #if self.Portfolio.CashBook["USD"].Amount < 1000 : # accountBalance = self.Portfolio.CashBook["USD"].Amount #else: # accountBalance = 1000 #quantity = self.positionSize(current_price, accountBalance,self.stopLossTarget, self.riskPercentage, pip) quantity = self.lotPositionSize(self.lotSize, pip) # BB bands lowerBand = self.BolingerData[symbol].LowerBand.Current.Value upperBand = self.BolingerData[symbol].UpperBand.Current.Value self.Debug('I made it here') # if current price is below or equals to lower band then take long position if current_price <= lowerBand: self.Debug('I made it here1') # Calculate stop loss and profit target stop_loss = current_price - (self.stopLossTarget * (pip * 10)) profit_target = current_price + (self.profitTarget * (pip * 10)) self.Debug('Long Position:') self.Debug(f'Position Size: {quantity}') self.Debug(f'Current Price: {current_price}') #self.Debug(f'Pip variance: {pip*10}') #self.Debug(f'Stop Loss Calc: {self.stopLossTarget * pip * 10}') self.Debug(f'Stop Loss: {stop_loss}') self.Debug(f'Profit Target: {profit_target}') #self.Plot(self.chart.Name, "Close", current_price) #self.Plot(self.chart.Name, "SMA", current_sma_value) if symbol == 'EURUSD': marketOrderTicket = self.MarketOrder(symbol, quantity) stopMarketOrderTicket = self.StopMarketOrder(symbol, -quantity, stop_loss) limitOrderTicket = self.LimitOrder(symbol, -quantity, profit_target) self.EURCurrentOrderTicket = marketOrderTicket self.EURStopLossTicket = stopMarketOrderTicket self.EURProfitTargetTicket = limitOrderTicket self.CurrentOrderTicket[symbol] = marketOrderTicket self.StopLossTicket[symbol] = stopMarketOrderTicket self.ProfitTargetTicket[symbol] = limitOrderTicket elif symbol == 'GBPUSD': marketOrderTicket = self.MarketOrder(symbol, quantity) stopMarketOrderTicket = self.StopMarketOrder(symbol, -quantity, stop_loss) limitOrderTicket = self.LimitOrder(symbol, -quantity, profit_target) self.GBPCurrentOrderTicket = marketOrderTicket self.GBPStopLossTicket = stopMarketOrderTicket self.GBPProfitTargetTicket = limitOrderTicket # if current price is above or equals to upper band then take short position elif current_price >= upperBand: self.Debug('I made it here2') # Calculate stop loss and profit target stop_loss = current_price + (self.stopLossTarget * (pip * 10)) profit_target = current_price - (self.profitTarget * (pip * 10)) self.Debug('Short Position:') self.Debug(f'Position Size: {quantity}') self.Debug(f'Current Price: {current_price}') #self.Debug(f'Pip variance: {pip*10}') #self.Debug(f'Stop Loss Calc: {self.stopLossTarget * pip * 10}') self.Debug(f'Stop Loss: {stop_loss}') self.Debug(f'Profit Target: {profit_target}') if symbol == 'EURUSD': marketOrderTicket = self.MarketOrder(symbol, -quantity) stopMarketOrderTicket = self.StopMarketOrder(symbol, quantity, stop_loss) limitOrderTicket = self.LimitOrder(symbol, quantity, profit_target) self.EURCurrentOrderTicket = marketOrderTicket self.EURStopLossTicket = stopMarketOrderTicket self.EURProfitTargetTicket = limitOrderTicket elif symbol == 'GBPUSD': marketOrderTicket = self.MarketOrder(symbol, -quantity) stopMarketOrderTicket = self.StopMarketOrder(symbol, quantity, stop_loss) limitOrderTicket = self.LimitOrder(symbol, quantity, profit_target) self.GBPCurrentOrderTicket = marketOrderTicket self.GBPStopLossTicket = stopMarketOrderTicket self.GBPProfitTargetTicket = limitOrderTicket def OnData(self, data: Slice): pass def OnOrderEvent(self, orderEvent): if orderEvent.Status != OrderStatus.Filled: return self.Debug(f"{self.Time} {orderEvent}") ## python doesn't support null. Instead, check for None if (self.EURProfitTargetTicket is None) or (self.EURStopLossTicket is None) or (self.GBPProfitTargetTicket is None) or (self.GBPStopLossTicket is None) : return filledOrderId = orderEvent.OrderId symbol = orderEvent.Symbol if symbol == 'EURUSD': self.Debug("Cancelling EURUSD Orders") if (self.EURProfitTargetTicket.OrderId == filledOrderId): self.EURStopLossTicket.Cancel() if (self.EURStopLossTicket.OrderId == filledOrderId): self.EURProfitTargetTicket.Cancel() elif symbol == 'GBPUSD': self.Debug("Cancelling GBPUSD Orders") if (self.GBPProfitTargetTicket.OrderId == filledOrderId): self.GBPStopLossTicket.Cancel() if (self.GBPStopLossTicket.OrderId == filledOrderId): self.GBPProfitTargetTicket.Cancel() # Close positions at the end of the day if in profit def closePositionsEndOfDay(self): for symbol in self.currencies: if self.Portfolio[symbol].Invested and self.Portfolio[symbol].UnrealizedProfitPercent > 0.02: unrealisedprofitpercent = self.Portfolio[symbol].UnrealizedProfitPercent self.Debug(f'Unrealised profit percent: {unrealisedprofitpercent}') if self.Portfolio[symbol].IsLong: self.MarketOrder(symbol, -self.Portfolio[symbol].Quantity) self.Debug(f"Closed {symbol} position at the end of the day") elif self.Portfolio[symbol].IsShort: self.MarketOrder(symbol, self.Portfolio[symbol].Quantity) self.Debug(f"Closed {symbol} position at the end of the day") # Close positions at the end of the week if in profit def closePositionsEndOfWeek(self): for symbol in self.currencies: if self.Portfolio[symbol].Invested and self.Portfolio[symbol].UnrealizedProfitPercent > 0.02: if self.Portfolio[symbol].IsLong: self.MarketOrder(symbol, -self.Portfolio[symbol].Quantity) self.Debug(f"Closed {symbol} position at the end of the week") elif self.Portfolio[symbol].IsShort: self.MarketOrder(symbol, self.Portfolio[symbol].Quantity) self.Debug(f"Closed {symbol} position at the end of the week") def positionSize(self,_price,_accountBalance, _stopLossPips, _riskPercentage, _minimumPriceVariation): # Debug Function Parameters # Calulate position size # based on risk percentage and account balance. ###############################################) _riskAmount = _accountBalance * _riskPercentage _riskValuePerPip = _riskAmount / _stopLossPips _positionSize = _riskValuePerPip / (_minimumPriceVariation * 10) self.Debug(f'Position Size: {_positionSize}') return _positionSize def lotPositionSize(self,_lot, _minimumPriceVariation): # Debug Function Parameters # Calulate position size using lots # based on risk percentage and account balance. ############################################### _positionSize = _lot / _minimumPriceVariation self.Debug(f'Position Size: {_positionSize}') self.Debug(f'Variance Size: {_minimumPriceVariation * 10}') return _positionSize