In [1]:
%matplotlib inline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
In [42]:
def load_data(filename):
df = pd.read_csv(filename)
df['Date'] = pd.to_datetime(df['Date'])
return df
def calcMax(length, high):
a = high.shape
runningMax = np.zeros(a)
runningMax[length-1] = max(high[:length])
for i in range(length,a[0]):
if high[i] >= runningMax[i-1]:
runningMax[i] = high[i]
elif runningMax[i-1] == high[i-length]:
runningMax[i] = max(high[(i-length+1):(i+1)])
else:
runningMax[i] = runningMax[i-1]
return runningMax
def calcMin(length, low):
a = low.shape
runningLow = np.zeros(a)
runningLow[length-1] = min(low[:length])
for i in range(length,a[0]):
if low[i] <= runningLow[i-1]:
runningLow[i] = low[i]
elif runningLow[i-1] == low[i-length]:
runningLow[i] = min(low[(i-length+1):(i+1)])
else:
runningLow[i] = runningLow[i-1]
return runningLow
def calcSignal(length, rm, rl, high, low):
a = rm.shape
signal = np.zeros(a)
for i in range(length,a[0]):
if high[i] >= rm[i-1]:
if low[i] < rl[i-1]:
signal[i] = 0
else:
signal[i] = 1
elif low[i] <= rl[i-1]:
signal[i] = -1
return signal
def calcDrawdown(portfolio):
a = portfolio.shape
drawdown = np.zeros(a)
prevPeak = portfolio[0]
for i in range(1,a[0]):
if portfolio[i] < prevPeak:
drawdown[i] = portfolio[i] - prevPeak
elif portfolio[i] > prevPeak:
prevPeak = portfolio[i]
return drawdown
def calcTrades(length, stopPct, signal, close, Open, high, low, rm, rl):
a = Open.shape
trade = np.zeros(a)
price = np.zeros(a)
currentPos = 0.0
prevPeak = 0.0
prevTrough = 0.0
for i in range(length,a[0]-1):
if currentPos == 0:
if signal[i] == 1:
trade[i] = 1
currentPos = 1
price[i] = max(rm[i-1], Open[i]);
prevPeak = price[i]
elif signal[i] == -1:
trade[i] = -1
currentPos = -1
price[i] = min(rl[i-1],Open[i]);
prevTrough = price[i]
elif currentPos == 1:
if high[i-1] > prevPeak:
prevPeak = high[i-1]
if low[i] <= (1-stopPct) * prevPeak:
trade[i] = -1
price[i] = min(Open[i], (1-stopPct)*prevPeak)
currentPos = 0
elif currentPos == -1:
if low[i-1] < prevTrough:
prevTrough = low[i-1]
if high[i] >= (1 + stopPct) * prevTrough:
trade[i] = 1
price[i] = max(Open[i], (1+stopPct)*prevTrough)
currentPos = 0
if currentPos == 1:
trade[a[0]-1] = -1
price[a[0]-1] = close[a[0]-1]
elif currentPos == -1:
trade[a[0]-1] = 1
price[a[0]-1] = close[a[0]-1]
# print(sum(abs(trade)) / 2)
return trade, price
def calcPortfolio(length, stopPct, Open, high, low, close, capital,contractSize,slippage):
runningMax = calcMax(length, high)
runningMin = calcMin(length, low)
signal = calcSignal(length, runningMax, runningMin, high, low)
trades,prices = calcTrades(length, stopPct, signal, close, Open, high, low, runningMax, runningMin)
a = Open.shape
port = np.zeros(a)
port[:length] = capital
cash = capital
currentPos = 0
priceTraded = 0
slippageThisTrade = 0
for i in range(length, a[0]):
port[i] = port[i-1] + currentPos*contractSize*(Open[i] - close[i-1])
if trades[i] == 1:
currentPos += 1
slippageThisTrade = (1-abs(currentPos))*slippage
priceTraded = prices[i]
port[i] = port[i] + currentPos*contractSize*(close[i] - priceTraded) - (1-abs(currentPos))*contractSize*(priceTraded - Open[i])
elif trades[i] == -1:
currentPos -= 1
slippageThisTrade = (1-abs(currentPos))*slippage
priceTraded = prices[i]
port[i] = port[i] + currentPos*contractSize*(close[i] - priceTraded) + (1-abs(currentPos))*contractSize*(priceTraded - Open[i])
elif trades[i] == 0:
slippageThisTrade = 0
port[i] = port[i] + currentPos*contractSize*(close[i]-Open[i])
return port
def backtest(df, pcts, lengths, cz, slippage, capital):
stopPct = 0
channelLength = 0
maxReturn = -10000000
for i in pcts:
for j in lengths:
port = calcPortfolio(int(j),i,np.array(df.Open),np.array(df.High),np.array(df.Low),np.array(df.Close), capital,cz,slippage)
ratio = (port[-1] - port[0]) / max(abs(calcDrawdown(port)))
if ratio > maxReturn:
stopPct = i
channelLength = j
maxReturn = ratio
return stopPct, channelLength
def predict(df, pct, channelLength, cz, slippage, capital):
portfolioVector = calcPortfolio(channelLength, pct,np.array(df.Open),np.array(df.High),np.array(df.Low),np.array(df.Close), capital,cz,slippage)
return portfolioVector
def strategy(df, cz, slippage, capital, pcts, lengths, insamp, outsamp):
insamp = np.timedelta64(insamp, 'Y')
outsamp = np.timedelta64(outsamp, 'M')
day = pd.Timedelta('1day')
val1 = df['Date'][0]
val2 = (df['Date'][0] + insamp + day).normalize()
val3 = (val2 + outsamp + day).normalize()
portfolio = np.array([])
while val2 <= df.Date[len(df.Date)-1]:
back = df[(df['Date'] >= val1) & (df['Date'] < val2)]
stopPct, channelLength = backtest(back, pcts, lengths, cz, slippage, capital)
back = df[(df['Date'] >= val2) & (df['Date'] < val3)]
portfolio = np.append(portfolio,predict(back, stopPct, channelLength, cz, slippage, capital))
capital = portfolio[-1]
val1 = (val1 + outsamp + day).normalize()
val2 = val3
val3 = (val3 + outsamp + day).normalize()
print(val2 < df.Date[len(df.Date)-1])
print('Done')
return portfolio
def optimize(df, cz, slippage, capital, pcts, lengths, insamp, outsamp):
maxReturn = 0
portfolio = 0
t = 0
tau = 0
for i in insamp:
for j in outsamp:
port = strategy(df, cz, slippage, captial, pcts, lengths, i, j)
ratio = (portfolio[-1] - portfolio[0]) / max(abs(calcDrawdown(port)))
if ratio > maxReturn:
portfolio = port
t = i
tau = j
maxReturn = ratop
return portfolio, t,tau
def runFile(opt, filename, cz, slippage, capital, pcts, lengths, insamp, outsamp):
df = load_data(filename)
if opt.lower() == 'strategy':
portfolio = strategy(df, cz, slippage, capital, pcts, lengths, insamp, outsamp)
return portfolio
elif opt.lower() == 'optimize':
portfolio, insample, outsample = optimize(df, cz, slippage, capital, pcts, lengths, insamp, outsamp)
return portfolio, insample, outsample
else:
print('Enter Either strategy or optimize')
In [3]:
filename = input("Enter Filename: ")
df = load_data(filename)
In [41]:
contractSize = 2000
slippage = 19
capital = 100000
#List of Stop Percents
pcts = [0.01,0.02]
#List of Channel Lengths
channelLength = [1000,1500]
# Enter in-sample in years
insample = 5
#Enter out-sample in months
outsample = 7
portfolio = strategy(df, contractSize, slippage, capital, pcts, channelLength, insample, outsample)
In [43]:
plt.plot(portfolio)
Out[43]:
In [ ]: