| Overall Statistics |
|
Total Trades 418 Average Win 1.51% Average Loss -0.78% Compounding Annual Return 23.101% Drawdown 14.400% Expectancy 0.308 Net Profit 59.487% Sharpe Ratio 1.159 Probabilistic Sharpe Ratio 55.292% Loss Rate 56% Win Rate 44% Profit-Loss Ratio 1.94 Alpha 0.18 Beta -0.015 Annual Standard Deviation 0.155 Annual Variance 0.024 Information Ratio 0.59 Tracking Error 0.255 Treynor Ratio -11.876 Total Fees $775.65 |
# https://quantpedia.com/Screener/Details/61
from QuantConnect.Data import SubscriptionDataSource
from QuantConnect.Python import PythonData
from datetime import date, timedelta, datetime
from decimal import Decimal
import numpy as np
import pandas as pd
import math
#import sys
class WeatherImportTest(QCAlgorithm):
def ExitPositions(self):
#If the market is open, use liquidate.
if self.Securities["SPY"].Exchange.ExchangeOpen == True:
#Liquidate all positions.
self.Liquidate()
#The above self.Liquidate only works during regular market hours. If there are still open positions, use limit orders to liquidate.
invested = [x.Key for x in self.Portfolio if x.Value.Invested]
if len(invested) > 0:
for symbol in invested:
security_holding = self.Portfolio[symbol]
quantity = security_holding.Quantity
if quantity > 0:
limit_price = self.Securities[symbol].Price * 0.99
self._limitTicket = self.LimitOrder(symbol, -1 * quantity, limit_price)
#Cancel any open orders too. Including sell orders, because if they haven't sold already, we probably need to adjust the price anyways.
openOrders = self.Transactions.GetOpenOrders()
if len(openOrders)> 0:
for x in openOrders:
if x.Quantity > 0: #only cancel buy orders
self.Transactions.CancelOrder(x.Id)
return
def getTradingMonth(self):
if self.Time.month < 4:
return True
elif self.Time.month > 10:
return True
else:
return False
return False
def getHDDDelta(self, data):
if data.ContainsKey("adjusted_hdd_delta"):
if not self.hdd_deltaWindow.IsReady:
self.hdd_deltaWindow.Add(self.Securities["adjusted_hdd_delta"].Price)
return False
# self.Debug(str('adding to window'))
elif int(self.Securities["adjusted_hdd_delta"].Price) == 0:
return False
#self.Debug(str('delta = 0'))
elif int(self.Securities["adjusted_hdd_delta"].Price) != int(self.hdd_deltaWindow[1]):
self.hdd_deltaWindow.Add(self.Securities["adjusted_hdd_delta"].Price)
#self.Debug(str(self.Time) + ' ' + str(self.hdd_deltaWindow[0]) + ' ' + str(self.hdd_deltaWindow[1]) + ' ' + str(self.hdd_deltaWindow[2]))
return float(self.Securities["adjusted_hdd_delta"].Price)
else:
return False
return False
def Buy(self, thisSecurity, cashPercentage, limit):
#If the market is open, use a market order.
if self.Securities["SPY"].Exchange.ExchangeOpen == True:
self.SetHoldings(thisSecurity, cashPercentage)
shares = self.Portfolio[thisSecurity].Quantity
limit_price = self.Securities[thisSecurity].Price
#Add stop loss and take profit
self.LimitOrder(thisSecurity, -shares, limit_price * (1.10))
self.StopMarketOrder(thisSecurity, -shares, limit_price * (0.90))
#If the market is in extended hours, use a limit order (market orders do not work during extended hours).
else:
return False #Enable this line to only do afternoon trades
equity = round(float(float(self.Portfolio.Cash) * cashPercentage),2)
limit_price = self.Securities[thisSecurity].Price * limit
if limit_price > 0:
shares = round(math.floor(equity / limit_price),2)
if shares > 0:
#self.Debug(str(self.Time) + " Cash="+str(self.Portfolio.Cash) + ' CashPct=' + str(cashPercentage) + ' Equity=' + str(equity) + ' LimitPrice=' + str(limit_price) + ' Shares= ' + str(shares))
self.LimitOrder(thisSecurity, shares, limit_price)
#take profit
self.LimitOrder(thisSecurity, -shares, limit_price * (1.10))
#stop loss
self.StopMarketOrder(thisSecurity, -shares, limit_price * (0.9))
self.Debug("post order")
return
def Initialize(self):
self.SetStartDate(2018, 1, 1) # Set Start Date
self.SetEndDate(2020, 3, 30)
self.SetCash(10000) # Set Strategy Cash
self.AddEquity("BOIL", Resolution.Minute, Market.USA, True, 0, True)
self.AddEquity("KOLD", Resolution.Minute, Market.USA, True, 0, True)
self.AddEquity("UGAZ", Resolution.Minute, Market.USA, True, 0, True)
self.AddEquity("DGAZ", Resolution.Minute, Market.USA, True, 0, True)
self.AddEquity("SPY", Resolution.Minute, Market.USA, True, 0, True)
self.Securities["BOIL"].SetDataNormalizationMode(DataNormalizationMode.Adjusted)
self.Securities["KOLD"].SetDataNormalizationMode(DataNormalizationMode.Adjusted)
self.Securities["UGAZ"].SetDataNormalizationMode(DataNormalizationMode.Adjusted)
self.Securities["DGAZ"].SetDataNormalizationMode(DataNormalizationMode.Adjusted)
self.Securities["SPY"].SetDataNormalizationMode(DataNormalizationMode.Adjusted)
#states = (self.GetParameter("states"))
self.AddData(Weather, "adjusted_hdd_delta", Resolution.Minute, fillDataForward=False)
# Every day at [time], liquidate all positions and cancel open orders.
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(9,55), Action(self.ExitPositions))
self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.At(15,55), Action(self.ExitPositions))
self._limitTicket = None
self.hdd_deltaWindow = RollingWindow[float](5)
self.SetTimeZone(TimeZones.NewYork)
#self.SetWarmUp(timedelta(7))
#self.OnWarmupFinished(timedelta(7))
def OnData(self, data):
#Declare variables
min_hdd_delta = int(self.GetParameter("min_hdd_delta"))
buy_limit = float(self.GetParameter("buy_limit"))
sell_limit = float(self.GetParameter("sell_limit"))
marketOpenToday = self.Securities["BOIL"].Exchange.Hours.IsDateOpen(self.Time) #Check if market is open today (at any time)
tradingMonth = self.getTradingMonth()
#Since our hdd_delta (the "price") can't be negative, we had to reset the HDD delta so all deltas are positive. 1509.25 is the "true zero" in the raw data from the csv.
#E.g. if the hdd_delta is > 1509.25, there's an increase in heating degree days.
zero = 1509.25
hdd_delta = self.getHDDDelta(data)
#If this is a trading month, and if the market is open today, and we have a hdd_delta, then trade.
if tradingMonth and marketOpenToday and bool(hdd_delta):
#If there are no open orders, initiate new trade.
#if len(self.Transactions.GetOpenOrders()) == 0:
#If the number of HDDs INCREASED, then the price of natgas will go up. Buy BOIL and sell KOLD.
if hdd_delta > zero + min_hdd_delta:
self.ExitPositions()
self.Buy("BOIL", 0.95, buy_limit)
#If the number of HDDs DECREASED, then the price of natgas will go up. Buy BOIL and sell KOLD.
elif hdd_delta < zero - min_hdd_delta:
self.ExitPositions()
self.Buy("KOLD", 0.95, buy_limit)
else:
pass
class Weather(PythonData):
def GetSource(self, config, date, isLive):
source = "https://www.dropbox.com/s/pytvxgb9pg272pw/quantconnect_hdd_export_dadstates.csv?dl=1" #Dad States
#source = "https://www.dropbox.com/s/9wgmkfrcci50kgl/quantconnect_hdd_export_allstates.csv?dl=1" #All States
return SubscriptionDataSource(source, SubscriptionTransportMedium.RemoteFile);
def Reader(self, config, line, date, isLive):
# If first character is not digit, pass
if not (line.strip() and line[0].isdigit()): return None
data = line.split(',')
weather = Weather()
weather.Symbol = config.Symbol
#weather.Time = datetime.strptime(data[0], '%Y%m%d %H:%M') + timedelta(hours=0)
weather.Time = datetime.strptime(data[0], '%Y-%m-%d %H:%M:%S') + timedelta(hours=-1)
weather.Value = float(data[8]) #dadstates
#weather.Value = float(data[4]) #allstates
#self.Log(str(weather.Time) + " " + str(weather.Value))
return weather# Your New Python File