Overall Statistics |
Total Trades 66 Average Win 0.76% Average Loss -1.04% Compounding Annual Return -51.820% Drawdown 13.800% Expectancy 0.118 Net Profit -5.033% Sharpe Ratio -1.323 Probabilistic Sharpe Ratio 21.041% Loss Rate 35% Win Rate 65% Profit-Loss Ratio 0.73 Alpha 0.059 Beta -0.486 Annual Standard Deviation 0.358 Annual Variance 0.128 Information Ratio -3.541 Tracking Error 0.443 Treynor Ratio 0.975 Total Fees $0.00 |
import clr clr.AddReference("System") clr.AddReference("QuantConnect.Algorithm") clr.AddReference("QuantConnect.Common") from System import * from QuantConnect import * from QuantConnect.Algorithm import * import numpy as np import torch import torch.nn.functional as F class PytorchNeuralNetworkAlgorithm(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 5, 7) # Set Start Date #self.SetEndDate(2020, 10, 8) # Set End Date #self.SetBrokerageModel(BrokerageName.OandaBrokerage) self.SetCash(1000000) # Set Strategy Cash # add symbol spy = self.AddForex("EURUSD", Resolution.Minute, Market.Oanda) spy1 = self.AddForex("USDCHF", Resolution.Minute, Market.Oanda) gug = self.AddForex("GBPUSD", Resolution.Minute, Market.Oanda) spy2 = self.AddForex("EURGBP", Resolution.Minute, Market.Oanda) #spy3 = self.AddForex("AUDUSD", Resolution.Minute, Market.Oanda) #spy4 = self.AddForex("EURAUD", Resolution.Minute, Market.Oanda) #spy5 = self.AddForex("AUDCHF", Resolution.Minute, Market.Oanda) #spy6 = self.AddForex("USDJPY", Resolution.Minute, Market.Oanda) #spy7 = self.AddForex("GBPJPY", Resolution.Minute, Market.Oanda) #spy8 = self.AddForex("AUDJPY", Resolution.Minute, Market.Oanda) #spy9 = self.AddForex("GBPAUD", Resolution.Minute, Market.Oanda) self.symbols = [spy.Symbol, spy1.Symbol, gug.Symbol, spy2.Symbol]#, spy3.Symbol, spy4.Symbol, spy5.Symbol, spy6.Symbol, spy7.Symbol, spy8.Symbol, spy9.Symbol]# using a list can extend to condition for multiple symbols# , self.lookback = 1440 # days of historical data (look back) self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday), self.TimeRules.Every(timedelta(minutes=480)), self.NetTrain) # train the NNself.TimeRules.AfterMarketOpen("EURUSD", 175), self.NetTrain) self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday), self.TimeRules.Every(timedelta(minutes=480)), self.Trade)# self.TimeRules.AfterMarketOpen("EURUSD", 179), self.Trade) self.SetWarmUp(self.lookback) stockPlot1 = Chart("Trade Plot") stockPlot1.AddSeries(Series("guess", SeriesType.Line, 0)) stockPlot1.AddSeries(Series("actual", SeriesType.Line, 0)) #stockPlot1.AddSeries(Series("rsiusd", SeriesType.Line, 0)) #stockPlot1.AddSeries(Series("liquidate", SeriesType.Line, 0)) #stockPlot1.AddSeries(Series("rsijpy", SeriesType.Line, 0)) #stockPlot1.AddSeries(Series("rsijpy1", SeriesType.Line, 0)) #stockPlot1.AddSeries(Series("rsijpy4", SeriesType.Line, 0)) self.AddChart(stockPlot1) def Ondata(self, data): if self.IsWarmingUp: return def NetTrain(self): # Daily historical data is used to train the machine learning model history = self.History(self.symbols, self.lookback + 1, Resolution.Minute) # dicts that store prices for training self.prices_x = {} self.prices_y = {} # dicts that store prices for sell and buy self.sell_prices = {} self.buy_prices = {} for symbol in self.symbols: if not history.empty: # x: preditors; y: response self.prices_x[symbol] = list(history.loc[symbol.Value]['open'])[:-1] self.prices_y[symbol] = list(history.loc[symbol.Value]['open'])[1:] for symbol in self.symbols: # if this symbol has historical data if symbol in self.prices_x: net = Net(n_feature=1, n_hidden=10, n_output=1) # define the network optimizer = torch.optim.SGD(net.parameters(), lr=0.2) loss_func = torch.nn.MSELoss() # this is for regression mean squared loss for t in range(200): # Get data and do preprocessing x = torch.from_numpy(np.array(self.prices_x[symbol])).float() y = torch.from_numpy(np.array(self.prices_y[symbol])).float() # unsqueeze data (see pytorch doc for details) x = x.unsqueeze(1) y = y.unsqueeze(1) prediction = net(x) # input x and predict based on x loss = loss_func(prediction, y) # must be (1. nn output, 2. target) optimizer.zero_grad() # clear gradients for next train loss.backward() # backpropagation, compute gradients optimizer.step() # apply gradients # Follow the trend self.buy_prices[symbol] = net(y)[-1] + np.std(y.data.numpy()) self.sell_prices[symbol] = net(y)[-1] - np.std(y.data.numpy()) def Trade(self): ''' Enter or exit positions based on relationship of the open price of the current bar and the prices defined by the machine learning model. Liquidate if the open price is below the sell price and buy if the open price is above the buy price ''' for holding in self.Portfolio.Values: if self.CurrentSlice[holding.Symbol].Open < self.sell_prices[holding.Symbol] and not holding.Invested: self.Plot("Trade Plot", "guess", self.sell_prices[holding.Symbol]) self.SetHoldings(holding.Symbol, 10 / len(self.symbols)) elif self.CurrentSlice[holding.Symbol].Open > self.buy_prices[holding.Symbol] and not holding.Invested: self.SetHoldings(holding.Symbol, -10 / len(self.symbols)) elif holding.Invested: if self.CurrentSlice[holding.Symbol].Open < self.sell_prices[holding.Symbol] and holding.IsShort: self.Liquidate(holding.Symbol) if self.CurrentSlice[holding.Symbol].Open > self.buy_prices[holding.Symbol] and holding.IsLong: self.Liquidate(holding.Symbol) self.Plot("Trade Plot", "actual", self.CurrentSlice["EURUSD"].Open) # class for Pytorch NN model class Net(torch.nn.Module): def __init__(self, n_feature, n_hidden, n_output): super(Net, self).__init__() self.hidden = torch.nn.Linear(n_feature, n_hidden) # hidden layer self.predict = torch.nn.Linear(n_hidden, n_output) # output layer def forward(self, x): x = F.relu(self.hidden(x)) # activation function for hidden layer x = self.predict(x) # linear output return x