Pair Trading - Exploring The Low Risk Statistical Arbitrage Trading Concepts

VJAY

Well-Known Member
There is space between get_newbeta and ( ). Please remove it. Also I will try to modify this function to give the actual buy and sell quantity instead of beta value. I am trying out a simple approach of managing the pairs...You can check my previous posts with backtest output...
Thanks bro ...yes its helpfull as we no need to use calculator :)
Also please make sure selling scrip always in future and buying scrip is in cash ...so in code we need to put lot size in selling scrip...so we get for buying scrips and qty ....
 
Last edited:

ncube

Well-Known Member
Thanks bro ...yes its helpfull as we no need to use calculator :)
Please update these 2 functions:

Code:
def get_qty(y,x,lb=20,amt=10000):
    ratio = y[-lb:] / x[-lb:]
    ratio_mean = ratio.mean()
    std_dev = ratio.std()
    zscore = (ratio- ratio_mean)/std_dev
    print('Latest zScore : ',zscore.iloc[-1])
    model_ols = sm.OLS(y[-lb:], x[-lb:]).fit()
    if zscore.iloc[-1] < 0 :
        yqty = int(amt/y.iloc[-1])
        xqty = int((amt/y.iloc[-1])*model_ols.params[0]) * -1
    else:
        yqty = int(amt/y.iloc[-1]) * -1
        xqty = int((amt/y.iloc[-1])*model_ols.params[0])
    print("%s Qty: " %y.name, yqty)
    print("%s Qty: " %x.name, xqty)

def getnew_zScore(SS1,SS2,SS1_price,SS2_price,lb=20,amt=10000):
    S1=SS1.append(pd.Series([SS1_price]),ignore_index=True)
    S2=SS2.append(pd.Series([SS2_price]),ignore_index=True)
    S1.name = SS1.name
    S2.name = SS2.name
    spread = S1[-lb:] / S2[-lb:]
    spread_mean = spread.mean()
    std_dev = spread.std()
    zscore = (spread - spread_mean)/std_dev
    get_qty(S1,S2,lb=20,amt=10000)
Now when you call the function:
Code:
SS1 = df['HINDZINC']
SS2 = df['NMDC']
getnew_zScore(SS1,SS2,275,103,20,10000)
The output will be:
Code:
Latest zScore :  0.24864342871878325
HINDZINC Qty:  -36
NMDC Qty:  96
The last value 10000 is the amt you want to invest in each stock in increments. I am trying a slightly different approach to managing the pairs. Instead of buying futures lots, I use cash and start with small increments. I.e at each eod, if the zscore is more than +/- 2.0 then I make adjustments. For the stock to be bought I take Positional trade and for the stock to be shorted, I short it in the morning as MIS order.
i.e after the 1st trade getnew_zScore(SS1,SS2,275,103,20,10000), if the zscore is more than +/-2.0 then I take the 2nd trade next day by investing another 10000. i.e getnew_zScore(SS1,SS2,275,103,20,20000) to get the new qty for the stocks.

Use getnew_zScore(SS1,SS2,275,103,20,10000) only if you want to make adjustment before eod, else you can just use get_beta(S1,S2,lb=20,amt=10000) after end of day to get the new qty for next day.

Code:
SS1 = df['HINDZINC']
SS2 = df['NMDC']
get_qty(SS1,SS2,20,10000);

Output:
Latest zScore :  0.5450456431905395
HINDZINC Qty:  -36
NMDC Qty:  96
 
Last edited:

VJAY

Well-Known Member
Dear ncube,
Thanks ...So everyday EOD you need to exit short scrip and again enter next morning....so if there is any gap opening its not disturbs pair trading?
 

ncube

Well-Known Member
Dear ncube,
Thanks ...So everyday EOD you need to exit short scrip and again enter next morning....so if there is any gap opening its not disturbs pair trading?
Yes, gaps will have adverse impact but since I short the stocks next day based on breakout of 1st 15/30 min candle, many times the shorts are not executed. So this compensates for the gap days as I will get to short on subsequent days at a better price.

BTW these are just my limited observations, I am also new to pair trading just 5-6 months into it ...:) I am trying out various approaches and sharing my learning here as I find the results are very encouraging. I am exploring pair trading as a viable strategy when markets are in sideways or in downtrend as all these years when the market is not favorable I used to just move my capital to liquid funds.
 

VJAY

Well-Known Member
Please update these 2 functions:

Code:
def get_beta(y,x,lb=20,amt=10000):
    ratio = y[-lb:] / x[-lb:]
    ratio_mean = ratio.mean()
    std_dev = ratio.std()
    zscore = (ratio- ratio_mean)/std_dev
    print('Latest zScore : ',zscore.iloc[-1])
    model_ols = sm.OLS(y[-lb:], x[-lb:]).fit()
    print("%s Qty: " %y.name, int(amt/y.iloc[-1]))
    print("%s Qty: " %x.name, int((amt/y.iloc[-1])*model_ols.params[0]))
    return(model_ols.params)

def getnew_zScore(SS1,SS2,SS1_price,SS2_price,lb=20,amt=10000):
    S1=SS1.append(pd.Series([SS1_price]),ignore_index=True)
    S2=SS2.append(pd.Series([SS2_price]),ignore_index=True)
    S1.name = SS1.name
    S2.name = SS2.name
    spread = S1[-lb:] / S2[-lb:]
    spread_mean = spread.mean()
    std_dev = spread.std()
    zscore = (spread - spread_mean)/std_dev
    print('Latest zScore : ',zscore.iloc[-1])
    get_beta(S1,S2,lb=20,amt=10000)
Now when you call the function:
Code:
SS1 = df['HINDZINC']
SS2 = df['NMDC']
getnew_zScore(SS1,SS2,275,103,20,10000)
The output will be:
Code:
Latest zScore :  0.24864342871878325
HINDZINC Qty:  36
NMDC Qty:  96
The last value 10000 is the amt you want to invest in each stock in increments. I am trying a slightly different approach to managing the pairs. Instead of buying futures lots, I use cash and start with small increments. I.e at each eod, if the zscore is more than +/- 2.0 then I make adjustments. For the stock to be bought I take Positional trade and for the stock to be shorted, I short it in the morning as MIS order.
i.e after the 1st trade getnew_zScore(SS1,SS2,275,103,20,10000), if the zscore is more than +/-2.0 then I take the 2nd trade next day by investing another 10000. i.e getnew_zScore(SS1,SS2,275,103,20,20000) to get the new qty for the stocks.

Use getnew_zScore(SS1,SS2,275,103,20,10000) only if you want to make adjustment before eod, else you can just use get_beta(S1,S2,lb=20,amt=10000) after end of day to get the new qty for next day.

Code:
SS1 = df['HINDZINC']
SS2 = df['NMDC']
get_beta(SS1,SS2,20,10000);

Output:
Latest zScore :  0.5450456431905395
HINDZINC Qty:  36
NMDC Qty:  96
Dear ncube,
above codes which one is correct/need us? one showing get beta and one showing get zscore?:confusedd:

1537506771059.png
 

ncube

Well-Known Member
Dear ncube,
above codes which one is correct/need us? one showing get beta and one showing get zscore?:confusedd:

View attachment 28609
I added getnew_zscore() as you had asked me earlier how to get the zscore if one updates the stock prices during the day.

get_beta() is the one to be used if you want to get the zscore and qty at eod. Actually now this function is directly giving the stock quantity instead of beta, so if you want to rename the function to get_qty()..its fine..:)
 

ncube

Well-Known Member
I added getnew_zscore() as you had asked me earlier how to get the zscore if one updates the stock prices during the day.

get_beta() is the one to be used if you want to get the zscore and qty at eod. Actually now this function is directly giving the stock quantity instead of beta, so if you want to rename the function to get_qty()..its fine..:)
I have added few more lines in the get_beta() function to give zscore value and specify whether its long or short, please update the function as I see that the output you have shared does not include it.
Code:
SS1 = df['HINDZINC']
SS2 = df['NMDC']
get_qty(SS1,SS2,20,10000);

Output:
Latest zScore :  0.5450456431905395
HINDZINC Qty:  -36
NMDC Qty:  96
Note: I am using my office laptop and I am using old stock data file so the zscore/long/short Qty will not match with yours.
 
Last edited:

VJAY

Well-Known Member
I have added few more lines in the get_beta() function to give zscore value and specify whether its long or short, please update the function as I see that the output you have shared does not include it.
Code:
SS1 = df['HINDZINC']
SS2 = df['NMDC']
get_beta(SS1,SS2,20,10000);

Output:
Latest zScore :  0.5450456431905395
HINDZINC Qty:  -36
NMDC Qty:  96
WHich line to be delete from function codes for remove double entry here ...from get beta or get zscore function?
1537508738197.png
 

VJAY

Well-Known Member
why here negative qty showing ...is its need to lower qty?

1537509525674.png