Advertisement
Nam_Hoang_Waw

Double Vol Breakout

Mar 2nd, 2019
307
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.04 KB | None | 0 0
  1. import pandas as pd
  2. import numpy as np
  3. import cmath as mt
  4. import pylab as pl
  5. from matplotlib import style
  6.  
  7. style.use('ggplot')
  8.  
  9. # Method of calculating PnL of Volatility Breakout:
  10.  
  11. def pnl(vect, slow, fast,std_interval,m):
  12.  
  13.     size = len(vect)
  14.  
  15.     df = pd.DataFrame(0,index=range(0, size),
  16.                          columns=['ClosePrice', 'diffPrice', 'fastMA', 'slowMA', 'rollstd', 'L_Bound', 'U_Bound', 'signalMoM', 'PL'])
  17.  
  18.     # Extracting Adjusted Close Price from the csv to the dataframe
  19.     n = 0
  20.     for i in vect:
  21.         df.ix[n, 'ClosePrice'] = i
  22.         n += 1
  23.  
  24.     # Calculating the first difference of the stock price movement
  25.     df['diffPrice'] = df['ClosePrice'].diff(1)
  26.  
  27.     # Calculating rolling mean of the fast moving average
  28.     n = 0
  29.     fastMA = pd.rolling_mean(vect, window=fast)
  30.     for i in fastMA:
  31.         df.ix[n, 'fastMA'] = i
  32.         n += 1
  33.  
  34.     # Calculating rolling mean of the slow moving average
  35.     n = 0
  36.     slowMA = pd.rolling_mean(vect, window=slow)
  37.     for i in slowMA:
  38.         df.ix[n, 'slowMA'] = i
  39.         n += 1
  40.  
  41.     # Calculating rolling mean of adjusted price
  42.     n = 0
  43.     rollstd = pd.rolling_std(vect, window=std_interval)
  44.     for i in rollstd:
  45.         df.ix[n, 'rollstd'] = i
  46.         n += 1
  47.  
  48.     # Calculating the lower band
  49.     n = 0
  50.     L_Bound = slowMA - m*rollstd
  51.     for i in L_Bound:
  52.         df.ix[n, 'L_Bound'] = i
  53.         n += 1
  54.  
  55.     # Calculating the upper band
  56.     n = 0
  57.     U_Bound = slowMA + m*rollstd
  58.     for i in U_Bound:
  59.         df.ix[n, 'U_Bound'] = i
  60.         n += 1
  61.  
  62.     if slow > std_interval:
  63.         count_nan = df.ix[:, 'slowMA'].isnull().sum()
  64.     else:
  65.         count_nan = df.ix[:, 'rollstd'].isnull().sum()
  66.  
  67.     n = count_nan
  68.  
  69.     df = df.dropna()
  70.  
  71.     # Signals of the volatility breakout:
  72.     for i in range(n + 1, size):
  73.         if df.ix[i - 1, 'signalMoM'] == 0 and df.ix[i - 1, 'fastMA'] > df.ix[i - 1, 'U_Bound']:
  74.             df.ix[i, 'signalMoM'] = 1
  75.         elif df.ix[i - 1, 'signalMoM'] == 0 and df.ix[i - 1, 'fastMA'] < df.ix[i - 1, 'L_Bound']:
  76.             df.ix[i, 'signalMoM'] = -1
  77.         elif df.ix[i - 1, 'signalMoM'] == 1 and df.ix[i - 1, 'fastMA'] > df.ix[i - 1, 'L_Bound']:
  78.             df.ix[i, 'signalMoM'] = 1
  79.         elif df.ix[i - 1, 'signalMoM'] == 1 and df.ix[i - 1, 'fastMA'] < df.ix[i - 1, 'L_Bound']:
  80.             df.ix[i, 'signalMoM'] = -1
  81.         elif df.ix[i - 1, 'signalMoM'] == -1 and df.ix[i - 1, 'fastMA'] < df.ix[i - 1, 'U_Bound']:
  82.             df.ix[i, 'signalMoM'] = -1
  83.         elif df.ix[i - 1, 'signalMoM'] == -1 and df.ix[i - 1, 'fastMA'] > df.ix[i - 1, 'U_Bound']:
  84.             df.ix[i, 'signalMoM'] = 1
  85.         else:
  86.             df.ix[i, 'signalMoM'] = 0
  87.  
  88.     # Calculating PnL:
  89.     for i in range(n + 1, size):
  90.         df.ix[i, 'PL'] = df.ix[i, 'signalMoM'] * df.ix[i, 'diffPrice']
  91.  
  92.     # Calculating cummulative PnL:
  93.     cummulativePL = df['PL'].cumsum(skipna=True)
  94.  
  95.     return cummulativePL
  96.  
  97. # Importing training period
  98. df1 = pd.read_csv("C:/Users/Desktop/Nam/AAPL_train.csv",delimiter= ',', thousands= ',')
  99.  
  100. # Extracting Adjusted Close Price and convert it to ndarray format
  101. vect = df1.ix[:, 'Adj Close'].values
  102.  
  103. # Setting up possible values for parameters:
  104. slow = np.arange(60,180,30)
  105. fast = np.arange(10,45,5)
  106. std_interval = np.arange(60,180,30)
  107. m = np.arange(1,2.5,0.5)
  108.  
  109. # Creating a dataframe that store PnL with corresponding parameters
  110. df = pd.DataFrame(index=range(0,20000),columns=['slow','fast','std_interval','m','PL'])
  111.  
  112. n = 0
  113.  
  114. for i in slow:
  115.     for j in fast:
  116.         for t in std_interval:
  117.             for x in m:
  118.                 df.ix[n, 'slow'] = i
  119.                 df.ix[n, 'fast'] = j
  120.                 df.ix[n, 'std_interval'] = t
  121.                 df.ix[n, 'm'] = x
  122.                 df.ix[n, 'PL'] = pnl(vect,i,j,t,x).iloc[-1]
  123.                 n += 1
  124.  
  125. result = df.sort_values(['PL'],ascending = False)
  126.  
  127. print (result.head())
  128.  
  129. # Best results are showed as followed:
  130.  
  131. #   slow    fast    std_interval    m       PL
  132. #   60      25      60              1       120.93
  133. #   120     40      90              1       120.536
  134. #   90      30      90              1       119.817
  135. #   90      25      90              1       117.067
  136. #   90      10      120             1       115.278
  137.  
  138. # The best set of parameters are (slow = 60, fast = 25, std_interval = 60, m = 1)
  139. df1 = pd.read_csv("C:/Users/Desktop/Nam/AAPL_test.csv",delimiter= ',', thousands= ',')
  140. vect = df1.ix[:, 'Adj Close'].values
  141.  
  142. # Calculating Buy and Hold cummulative sum and PnL over the holding period:
  143. BuyAndHold_PL = np.diff(vect)
  144. BuyAndHold_cumSum = BuyAndHold_PL.cumsum()
  145. BuyAndHold_totalPL = vect[-1] - vect[0]
  146.  
  147. # Creating indexes for Buy and Hold strategy and Volatility break out strategy:
  148. index1 = np.arange(0,len(pnl(vect,60,25,60,1)),1)
  149. index2 = np.arange(0,len(BuyAndHold_cumSum),1)[59:len(BuyAndHold_cumSum)]-59
  150.  
  151. # Defining the starting index of both strategies:
  152. BuyAndHold_cumSum = BuyAndHold_cumSum[59:len(BuyAndHold_cumSum)]
  153. Double_Vol_CumSumPL = pnl(vect,60,25,60,1)
  154.  
  155. # Plotting Cummulative PnL of Vol Breakout against Buy and Hold strategy:
  156. pl.plot(index1,Double_Vol_CumSumPL,'r',label = 'Volatility Breakout cumulative PnL',linestyle='--')
  157. pl.plot(index2,BuyAndHold_cumSum,'b', label = 'Buy n Hold cumulative PnL')
  158. pl.legend(loc='top right')
  159. pl.show()
  160.  
  161. # Risk free rate from 2009-2015:
  162. # Source: http://www.multpl.com/10-year-treasury-rate/table/by-year
  163.  
  164. annual_Rf = [0.0252,0.0373,0.0339,0.0197,0.0191,0.0286,0.0188,0.0209]
  165.  
  166. # Converting annual risk free rate to daily risk free rate:
  167. daily_annual_Rf = np.mean(annual_Rf)/252
  168.  
  169. # Calculating Sharpe ratio:
  170. PnL = np.diff(Double_Vol_CumSumPL)
  171. PnL = np.delete(PnL,[0])
  172. vect = vect[60:len(vect)-1]
  173.  
  174. PortfolioReturn = []
  175.  
  176. for i in range(0,len(vect)):
  177.     PortfolioReturn.append(PnL[i]/vect[i])
  178.  
  179. mean_excess_return = np.nanmean(PortfolioReturn)
  180.  
  181. excess_return_std = np.nanstd(np.subtract(PortfolioReturn, daily_annual_Rf))
  182.  
  183. SharpeRatio = mt.sqrt(252) * (mean_excess_return - daily_annual_Rf) / excess_return_std
  184.  
  185. print (SharpeRatio)
  186.  
  187. #Sharpe Ratio is 0.67
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement