Overall Statistics |
Total Trades 8 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $8.00 Estimated Strategy Capacity $0 Lowest Capacity Asset AAPL.EODDATA 2S |
from asyncio import FastChildWatcher from AlgorithmImports import * import numpy as np from dateutil.parser import parse class FormalRedChicken(QCAlgorithm): def Initialize(self): self.SetStartDate(2021, 11, 1) # Set Start Date self.SetEndDate(2021, 11, 1) self.SetCash(10000) # Set Strategy Cash self.symbol = self.AddData(EODDATA, "AAPL", Resolution.Minute).Symbol self.sum = 0 #self.sum_n = 0 self.tick_list = [] self.tick_seq = [] #self.tick_list_n = [] #self.tick_seq_n = [] self.ts = int(self.GetParameter("tick_size")) #self.ts_n = int(self.GetParameter("tick_size_n")) self.window_size = int(self.GetParameter("window_size")) #self.window_size_n = int(self.GetParameter("window_size_n")) self.next_positive_prob = 0 self.next_negative_prob = 0 #Reality Modeling self.interests = self.AddData(DFFData, "INT", Resolution.Daily).Symbol #Benchmark self.SetBenchmark(self.AddEquity("SPY").Symbol) #IB Fee model self.Securities[self.symbol].SetFeeModel(CustomFeeModel()) #Set slippage model self.Securities[self.symbol].SetSlippageModel(ConstantSlippageModel(0.0002)) #Set Leverage interest model self.Securities[self.symbol].MarginModel = BuyingPowerModel(2.0, 0.05) self.cash_rate = 0.005 self.leverage_rate = .0075 self.short_rate = 0.0025 self.leverage_costs = 0 self.cash_interests = 0 self.short_costs = 0 self.max_leverage = 2 self.qt_factor = float(self.GetParameter("qt")) #Schedule events self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(0,0), self.Cash_Rebalance) self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(20,0), self.Leverage_Rebalance) self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(20,0), self.Short_Rebalance) self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.Every(TimeSpan.FromHours(int(self.GetParameter("prob_rebalance")))), self.Get_Probabilities) self.debug = True def OnData(self, data): if not data.ContainsKey(self.symbol): return if self.debug: self.Debug(f"Last price: {data[self.symbol].Value}") self.Debug(f"Last qty: {data[self.symbol].GetProperty('Volume')}") self.tick_list.append(data[self.symbol].Value) self.sum = self.sum + data[self.symbol].GetProperty('Volume') #self.tick_list_n.append(data[self.symbol].Value) #self.sum_n = self.sum_n + data[self.symbol].GetProperty('Volume') if self.sum >= self.ts: self.sum = 0 if self.tick_list[0] < self.tick_list[-1]: self.tick_seq.append(1) else: self.tick_seq.append(-1) self.tick_list.clear() if self.debug: self.Debug('New Tick! (pos)') self.Debug('Tick seq ' + str(self.tick_seq)) self.Debug('Sum ' + str(sum(self.tick_seq[-(self.window_size):]))) total_leverage = float(self.Portfolio.TotalPortfolioValue) * self.max_leverage qt = (total_leverage * (float(self.qt_factor)/self.max_leverage)) / data[self.symbol].Value if self.next_positive_prob > 0.6: if not self.Portfolio.Invested: if sum(self.tick_seq[-(self.window_size):]) == self.window_size: self.MarketOrder(self.symbol, qt) #if self.debug: self.Debug('Bought ' +str(qt)+ ' stocks at ' + str(data[self.symbol].Value)) else: if self.Portfolio[self.symbol].IsLong: if self.tick_seq[-1]==-1: self.Liquidate() #if self.debug: self.Debug('Liqudated') #if self.sum_n >= self.ts_n: # self.sum_n = 0 # if self.tick_list_n[0] < self.tick_list_n[-1]: # self.tick_seq_n.append(1) # else: # self.tick_seq_n.append(-1) # self.tick_list_n.clear() # if self.debug: # self.Debug('New Tick! (neg)') # self.Debug('Tick seq ' + str(self.tick_seq_n)) # self.Debug('Sum ' + str(sum(self.tick_seq_n[-(self.window_size_n):]))) # total_leverage = float(self.Portfolio.TotalPortfolioValue) * self.max_leverage # qt = (total_leverage * (float(self.qt_factor)/self.max_leverage)) / data[self.symbol].Value if self.next_negative_prob > 0.6: if not self.Portfolio.Invested: if sum(self.tick_seq[-(self.window_size):]) == -self.window_size: self.MarketOrder(self.symbol, -qt) #if self.debug: self.Debug('Shorted ' +str(qt)+ ' stocks at ' + str(data[self.symbol].Value)) else: if self.Portfolio[self.symbol].IsShort: if self.tick_seq[-1]==1: self.SetHoldings(self.symbol, 0) if self.debug: self.Debug('Stoped short') def OnEndOfAlgorithm(self): self.ExitPositions() def ExitPositions(self): self.Liquidate() self.Debug('TRADING FEES: ' + str(self.Portfolio[self.symbol].TotalFees)) self.Debug('LEVERAGE COSTS: ' + str(self.leverage_costs)) self.Debug('CASH INTERESTS: ' + str(self.cash_interests)) self.Debug('SHORT COSTS: ' + str(self.short_costs)) def Cash_Rebalance(self): if not self.Portfolio.Invested: data = self.Securities[self.interests].GetLastData() if data: cash = self.Portfolio.Cash interest_rate = (data.Value / 100 - self.cash_rate)/360 if interest_rate < 0: return else: self.Portfolio.CashBook["USD"].AddAmount(cash * interest_rate) self.cash_interests += cash * interest_rate if self.debug: self.Debug('Interest '+str(interest_rate)) self.Debug("Cash int " + str(cash * interest_rate)) def Leverage_Rebalance(self): if self.Portfolio.Invested: data = self.Securities[self.interests].GetLastData() if data: cash = self.Portfolio.Cash interest_rate = (data.Value / 100 + self.leverage_rate)/360 self.Portfolio.CashBook["USD"].AddAmount(cash * interest_rate) self.leverage_costs += cash * interest_rate if self.debug: self.Debug('Interest '+str(interest_rate)) self.Debug("Leverage int " + str(cash * interest_rate)) def Short_Rebalance(self): if self.Portfolio[self.symbol].IsShort: Last_order = self.Transactions.LastOrderId mkt_value = self.Transactions.GetOrderTicket(Last_order).AverageFillPrice * self.Transactions.GetOrderTicket(Last_order).QuantityFilled interest = self.short_rate / 360 self.short_costs += mkt_value * interest self.Portfolio.CashBook["USD"].AddAmount(mkt_value * interest) if self.debug: self.Debug('Portfolio is short') self.Debug('Short Interest ' + str(mkt_value * interest)) def Get_Probabilities(self): if len(self.tick_seq) == 0: return self.tick_idx = [i for i in range(len(self.tick_seq))] window_total = 0 positive_ticks = 0 next_positive = 0 negative_ticks = 0 next_negative = 0 for i in range(self.window_size ,len(self.tick_seq)+1): window_total = np.sum( self.tick_seq[i-self.window_size:i-1] ) if window_total == self.window_size-1: positive_ticks += 1 if self.tick_seq[i-1] == 1: next_positive += 1 elif -window_total == self.window_size-1: negative_ticks += 1 if self.tick_seq[i-1] == -1: next_negative += 1 if positive_ticks == 0: self.next_positive_prob = 0 else: self.next_positive_prob = next_positive/positive_ticks if negative_ticks == 0: self.next_negative_prob=0 else: self.next_negative_prob = next_negative /negative_ticks if self.debug: self.Debug('Window size ' + str(self.window_size)) self.Debug('Tick size ' + str(self.ts)) self.Debug('Total ticks ' + str(len(self.tick_seq))) self.Debug(str(self.window_size-1) + ' positive ticks in a row probability: ' + str(positive_ticks/len(self.tick_seq)) + ', '+ str(self.window_size-1) + ' negative ticks in a row prob. ' + str(negative_ticks/len(self.tick_seq))) self.Debug(str(self.window_size) +' positive probability: ' + str(self.next_positive_prob) +' ' + str(self.window_size) +' negative probability ' + str(self.next_negative_prob)) #self.Debug(str(self.next_positive) +' ' + str(self.next_negative)) class CustomFeeModel: def GetOrderFee(self, parameters): if parameters.Order.Quantity > 0: fee = min(max(1, parameters.Order.AbsoluteQuantity * 0.005), parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.01) elif parameters.Order.Tag == 'Liquidated': fee = min(max(1, parameters.Order.AbsoluteQuantity * 0.005), parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.01) elif parameters.Order.Quantity < 0: fee = min(max(1, parameters.Order.AbsoluteQuantity * 0.005), parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.01) else: fee = 0 return OrderFee(CashAmount(fee, 'USD')) class DFFData(PythonData): def GetSource(self, config, date, isLiveMode): source = "https://www.dropbox.com/s/n4beqe9zlcv0y4t/DFF.csv?dl=1" return SubscriptionDataSource( source, SubscriptionTransportMedium.RemoteFile) #rest for live data def Reader(self, config, line, date, isLiveMode): if not (line.strip() and line[0].isdigit()): return None data = line.split(',') coin = DFFData() coin.Symbol = config.Symbol coin.Time = parse(data[0]) coin.Value = float(data[1]) return coin class EODDATA(PythonData): def GetSource(self, config, date, isLiveMode): source = "https://www.dropbox.com/s/6hma23a7tnrkbph/AMZN_1m_2004-01-01_2022-03-01.csv?dl=1" return SubscriptionDataSource( source, SubscriptionTransportMedium.RemoteFile) def Reader(self, config, line, date, isLiveMode): if not (line.strip() and line[0].isdigit()): return None data = line.split(',') coin = EODDATA() coin.Symbol = config.Symbol coin.Time = parse(data[0]) coin.Value = float(data[4]) coin["Volume"] = float(data[5]) return coin