Skip to content

Commit b5675bd

Browse files
committed
Update strategy library tutorial QuantConnect#2 to PEP8
1 parent 6758098 commit b5675bd

File tree

2 files changed

+72
-69
lines changed

2 files changed

+72
-69
lines changed

04 Strategy Library/02 Combining Mean Reversion and Momentum in Forex Market/03 Method.html

Lines changed: 71 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,32 @@
44

55
<h3>Step 1: Request Historical Data</h3>
66
<p>
7-
The first function takes two arguments: symbol and number of daily data points requested. This function requests historical <a href="https://www.quantconnect.com/docs#Consolidating-Data-TradeBars-vs-QuoteBars">QuoteBars</a> and builds it into a pandas DataFrame. For more information about pandas DataFrame, please refer to the help documentation <a href="http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.html">DataFrame</a>. The calculate_return function takes a DataFrame as an argument to calculate the mean and standard deviation of the log prices, and create new columns for the DataFrame (return, reversal factor and momentum) - it prepares the DataFrame for multiple linear regression.
7+
The first function takes two arguments: symbol and number of daily data points requested. This function requests historical <a href="https://www.quantconnect.com/docs#Consolidating-Data-TradeBars-vs-QuoteBars">QuoteBars</a> and builds it into a pandas DataFrame. For more information about pandas DataFrame, please refer to the help documentation <a href="http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.html">DataFrame</a>. The <code>_calculate_return</code> function takes a DataFrame as an argument to calculate the mean and standard deviation of the log prices, and create new columns for the DataFrame (return, reversal factor and momentum) - it prepares the DataFrame for multiple linear regression.
88
</p>
99
<div class="section-example-container">
1010

11-
<pre class="python">def get_history(self,symbol, num):
11+
<pre class="python">def _get_history(self,symbol, num):
1212
data = {}
1313
dates = []
14-
history = self.History([symbol], num, Resolution.Daily).loc[symbol]['close'] #request the historical data for a single symbol
14+
history = self.history([symbol], num, Resolution.DAILY).loc[symbol]['close'] #request the historical data for a single symbol
1515
for time in history.index:
1616
t = time.to_pydatetime().date()
1717
dates.append(t)
18-
dates = pd.to_datetime(dates)
18+
dates = pd.to_datetime(dates)
1919
df = pd.DataFrame(history)
2020
df.reset_index(drop=True)
2121
df.index = dates
2222
df.columns = ['price']
23+
2324
return df
2425

25-
def calculate_return(self,df):
26+
def _calculate_return(self,df):
2627
#calculate the mean for further use
2728
mean = np.mean(df.price)
2829
# cauculate the standard deviation
2930
sd = np.std(df.price)
3031
# pandas method to take the last datapoint of each month.
31-
df = df.resample('BM',how = lambda x: x[-1])
32+
df = df.resample('BM').last()
3233
# the following three lines are for further experiment purpose
3334
# df['j1'] = df.price.shift(1) - df.price.shift(2)
3435
# df['j2'] = df.price.shift(2) - df.price.shift(3)
@@ -45,67 +46,69 @@ <h3>Step 1: Request Historical Data</h3>
4546

4647
<h3>Step 2: Build Predictive Model</h3>
4748
<p>
48-
The concat function requests history and joins the results into a single DataFrame. As \(\mu \) varies by country so we assign the mean and standard deviation to the symbol for each currency for future use. The OLS function takes the resulting DataFrame to conduct an OLS regression. We write it into a function because it's easier to change the formula here if we need.
49+
The <code>_concat</code> function requests history and joins the results into a single DataFrame. As \(\mu \) varies by country so we assign the mean and standard deviation to the symbol for each currency for future use. The OLS function takes the resulting DataFrame to conduct an OLS regression. We write it into a function because it's easier to change the formula here if we need.
4950
</p>
5051

5152
<div class="section-example-container">
5253

53-
<pre class="python">def concat(self):
54+
<pre class="python">def _concat(self):
5455
# we requested as many daily tradebars as we can
55-
his = self.get_history(self.quoted[0].Value,20*365)
56+
his = self._get_history(self._quoted[0].value,20*365)
5657
# get the clean DataFrame for linear regression
57-
his = self.calculate_return(his)
58+
his = self._calculate_return(his)
5859
# add property to the symbol object for further use.
59-
self.quoted[0].mean = his[1]
60-
self.quoted[0].sd = his[2]
60+
self._quoted[0].mean = his[1]
61+
self._quoted[0].sd = his[2]
6162
df = his[0]
6263
# repeat the above procedure for each symbols, and concat the dataframes
63-
for i in range(1,len(self.quoted)):
64-
his = self.get_history(self.quoted[i].Value,20*365)
65-
his = self.calculate_return(his)
66-
self.quoted[i].mean = his[1]
67-
self.quoted[i].sd = his[2]
64+
for i in range(1,len(self._quoted)):
65+
his = self._get_history(self._quoted[i].value,20*365)
66+
his = self._calculate_return(his)
67+
self._quoted[i].mean = his[1]
68+
self._quoted[i].sd = his[2]
6869
df = pd.concat([df,his[0]])
6970
df = df.sort_index()
7071
# remove outliers that outside the 99.9% confidence interval
71-
df = df[df.apply(lambda x: np.abs(x - x.mean()) / x.std() &lt; 3).all(axis=1)]
72+
df = df[df.apply(lambda x: np.abs(x - x.mean()) / x.std() < 3).all(axis=1)]
7273
return df
7374

74-
def OLS(self,df):
75-
res = sm.ols(formula = 'return ~ reversal + mom',data = df).fit()
75+
def _OLS(self,df):
76+
res = sm.ols(formula = 'log_return ~ reversal + mom',data = df).fit()
7677
return res</pre>
7778
</div>
7879

7980
<h3>Step 3: Apply Predictive Model</h3>
8081
<p>
81-
The predict function uses the history for the last 3 months, merges it into a DataFrame and then calculates the updated factors. Using these updated factors (together with the model we built) we calculate the expected return.
82+
The <code>_predict</code> function uses the history for the last 3 months, merges it into a DataFrame and then calculates the updated factors. Using these updated factors (together with the model we built) we calculate the expected return.
8283
</p>
8384
<div class="section-example-container">
8485

85-
<pre class="python">def predict(self,symbol):
86+
<pre class="python">def _predict(self,symbol):
8687
# get current month in string
87-
month = str(self.Time).split(' ')[0][5:7]
88+
month = str(self.time).split(' ')[0][5:7]
8889
# request the data in the last three months
89-
res = self.get_history(symbol.Value,33*3)
90+
res = self._get_history(symbol.value,33*3)
9091
# pandas method to take the last datapoint of each month
91-
res = res.resample('BM',how = lambda x: x[-1])
92+
res = res.resample('BM').last()
9293
# remove the data points in the current month
9394
res = res[res.index.month != int(month)]
9495
# calculate the variables
95-
res = self.calculate_input(res,symbol.mean,symbol.sd)
96-
res = res.ix[0]
96+
res = self._calculate_input(res,symbol.mean,symbol.sd)
97+
res = res.iloc[0]
9798
# take the coefficient. The first one will not be used for sum-product because it's the intercept
98-
params = self.formula.params[1:]
99+
params = self._formula.params[1:]
99100
# calculate the expected return
100-
re = sum([a*b for a,b in zip(res[1:],params)]) + self.formula.params[0]
101+
re = sum([a*b for a,b in zip(res[1:],params)]) + self._formula.params[0]
101102
return re
102103

103-
def calculate_input(self, df, mean, sd):
104+
def _calculate_input(self,df,mean,sd):
105+
# df['j1'] = df.price - df.price.shift(1)
106+
# df['j2'] = df.price.shift(1) - df.price.shift(2)
107+
# df['j3'] = df.price.shift(2) - df.price.shift(3)
104108
df['reversal'] = (df.price - mean)/sd
105109
df['mom'] = df.price - df.price.shift(3)
106110
df = df.dropna()
107-
return df
108-
</pre>
111+
return df</pre>
109112
</div>
110113

111114
<p>
@@ -121,29 +124,30 @@ <h3>Step 3: Apply Predictive Model</h3>
121124

122125
<h3>Step 4: Initializing the Model</h3>
123126
<p>
124-
In the Initialize function we prepare the data and conduct a linear regression. The class property 'self.formula' is the result of the OLS regression. We will use this object each time we rebalance the portfolio.
127+
In the <a href='/docs/v2/writing-algorithms/initialization'>initialize</a> function we prepare the data and conduct a linear regression. The class property <code>self._formula</code> is the result of the OLS regression. We will use this object each time we rebalance the portfolio.
125128
</p>
126129

127130
<div class="section-example-container">
128131

129-
<pre class="python">def Initialize(self):
130-
self.SetStartDate(2013,6,1)
131-
self.SetEndDate(2016,6,1)
132-
self.SetCash(10000)
133-
self.syls = ['EURUSD','GBPUSD','USDCAD','USDJPY']
134-
self.quoted = []
135-
for i in range(len(self.syls)):
136-
self.quoted.append(self.AddForex(self.syls[i],Resolution.Daily,Market.Oanda).Symbol)
137-
df = self.concat()
138-
self.Log(str(df))
139-
self.formula = self.OLS(df)
140-
self.Log(str(self.formula.summary()))
141-
self.Log(str(df))
142-
self.Log(str(df.describe()))
143-
for i in self.quoted:
144-
self.Log(str(i.mean) + ' ' + str(i.sd))
145-
self.Schedule.On(self.DateRules.MonthStart(), self.TimeRules.At(9,31), Action(self.action))
146-
</pre>
132+
<pre class="python">def initialize(self):
133+
self.set_start_date(2013,6,1)
134+
self.set_end_date(2016,6,1)
135+
self.set_cash(10000)
136+
syls = ['EURUSD','GBPUSD','USDCAD','USDJPY']
137+
self._quoted = []
138+
for i in range(len(syls)):
139+
self._quoted.append(self.add_forex(syls[i],Resolution.DAILY,Market.OANDA).symbol)
140+
141+
df = self._concat()
142+
self.log(str(df))
143+
self._formula = self._OLS(df)
144+
self.log(str(self._formula.summary()))
145+
self.log(str(df))
146+
self.log(str(df.describe()))
147+
for i in self._quoted:
148+
self.log(str(i.mean) + ' ' + str(i.sd))
149+
150+
self.schedule.on(self.date_rules.month_start(), self.time_rules.at(9,31), self._action)</pre>
147151
</div>
148152

149153
<h3>Step 5: Performing Monthly Rebalancing</h3>
@@ -153,27 +157,26 @@ <h3>Step 5: Performing Monthly Rebalancing</h3>
153157

154158
<div class="section-example-container">
155159

156-
<pre class="python">def action(self):
160+
<pre class="python">def _action(self):
157161
rank = []
158162
long_short = []
159-
for i in self.quoted:
160-
rank.append((i,self.predict(i)))
161-
# rank the symbols by their expected return
163+
for i in self._quoted:
164+
rank.append((i,self._predict(i)))
165+
# rank the symbols by their expected return
162166
rank.sort(key = lambda x: x[1],reverse = True)
163-
# the first element in long_short is the one with the highest expected return, which we are going to long, and the second one is going to be shorted.
167+
# the first element in long_short is the one with the highest expected return, which we are going to long, and the second one is going to be shorted.
164168
long_short.append(rank[0])
165169
long_short.append(rank[-1])
166-
self.Liquidate()
167-
168-
# the product &lt; 0 means the expected return of the first one is positive and that of the second one is negative--we are going to long and short.
169-
if long_short[0][1]*long_short[1][1] &lt; 0:
170-
self.SetHoldings(long_short[0][0],1)
171-
self.SetHoldings(long_short[1][0],-1)
172-
# this means we long only because all of the expected return is positive
173-
elif long_short[0][1] &gt; 0 and long_short[1][1] &gt; 0:
174-
self.SetHoldings(long_short[0][0],1)
175-
# short only
170+
self.liquidate()
171+
172+
# the product < 0 means the expected return of the first one is positive and that of the second one is negative--we are going to long and short.
173+
if long_short[0][1]*long_short[1][1] < 0:
174+
self.set_holdings(long_short[0][0],1)
175+
self.set_holdings(long_short[1][0],-1)
176+
# this means we long only because all of the expected return is positive
177+
elif long_short[0][1] > 0 and long_short[1][1] > 0:
178+
self.set_holdings(long_short[0][0],1)
179+
# short only
176180
else:
177-
self.SetHoldings(long_short[1][0],-1)
178-
</pre>
181+
self.set_holdings(long_short[1][0],-1)</pre>
179182
</div>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<div class="qc-embed-frame" style="display: inline-block; position: relative; width: 100%; min-height: 100px; min-width: 300px;">
22
<div class="qc-embed-dummy" style="padding-top: 56.25%;"></div>
33
<div class="qc-embed-element" style="position: absolute; top: 0; bottom: 0; left: 0; right: 0;">
4-
<iframe class="qc-embed-backtest" height="100%" width="100%" style="border: 1px solid #ccc; padding: 0; margin: 0;" src="https://www.quantconnect.com/terminal/processCache/embedded_backtest_73883ad731bcac43e1a94b3983b5f8ca.html"></iframe>
4+
<iframe class="qc-embed-backtest" height="100%" width="100%" style="border: 1px solid #ccc; padding: 0; margin: 0;" src="https://www.quantconnect.com/terminal/processCache?request=embedded_backtest_7c51024e7c791dfacbb9bef49571af13.html"></iframe>
55
</div>
66
</div>

0 commit comments

Comments
 (0)