mercredi 24 juin 2020

Backtesting stocks portfolio problem if conditions

First of all my goal is not trading but I want to understand how to create a backtest on python.

So my objective is coding only and understanding what is wrong with my code.

I assume that there is no transaction fees and that you can buy a fraction of a stock.

I have this DataFrame:

df=pd.DataFrame({'Date':['2017-05-19','2017-05-22','2017-05-23','2017-05-24','2017-05-25','2017-05-26','2017-05-29'],
                 'Apple':[153.67,152.76,153.18,155.45,153.93,154.45,155.37],
                 'Facebook':[139.72,137.43,141,141.55,141.81,142.15,142.06],})

df['Date']=pd.to_datetime(df['Date'])
df = df.set_index('Date')

And I have done my backtest by coding this way:

def backtesting(stock,capital):
    df_init=(stock*0).assign(cash=0)
    df_end=(stock*0).assign(cash=0)
    
    df_init.iloc[0,df_init.columns.get_loc('cash')]=capital
    df_end.iloc[0,df_end.columns.get_loc('cash')]=capital
    
    SMA_2=stock.rolling(2).mean().fillna(0)
    SMA_1=stock.rolling(1).mean().fillna(0)
    
    calendar=pd.Series(df_init.index)[1:]
    
    for date in calendar:
        for cols in stock:
            
            prev_date=df_init.index[df_init.index<date][-1]
            df_init.loc[date,:]=df_end.loc[prev_date,:]
            M=2 #number of securities
            count = (df_init.loc[date,stock.columns]!=0).sum()
            
            #Weight
            if count != M:
                weight = 1/(M-count)
            else:
                weight = 1
            
            #Portfolio
            portfolio = stock.loc[date,cols]*df_init.loc[date,cols]+df_init.loc[date,'cash']*weight
            
            #Conditions
            if SMA_1.loc[date,cols] > SMA_2.loc[date,cols] and df_init.loc[date,cols]==0:
                df_end.loc[date,cols]=portfolio/stock.loc[date,cols]
                df_end.loc[date,'cash']=df_init.loc[date,'cash'] - df_end.loc[date,cols]*stock.loc[date,cols]
            
            elif SMA_1.loc[date,cols] > SMA_2.loc[date,cols] and df_init.loc[date,cols]!=0:
                df_end.loc[date,cols]=df_init.loc[date,cols]
                df_end.loc[date,'cash']=df_init.loc[date,'cash']
            
            else:
                df_end.loc[date,cols]=0
                df_end.loc[date,'cash']=df_init.loc[date,cols]*stock.loc[date,cols]+df_init.loc[date,'cash']
    
    return df_end

And then in order to see the DataFrame:

backtesting(df,10000)

However this is the problem that I have, when you look at the DataFrame you have this:

             Apple      Facebook       cash
Date            
2017-05-19  0.000000    0.000000    10000.000000
2017-05-22  0.000000    0.000000    10000.000000
2017-05-23  32.641337   35.460993   5000.000000
2017-05-24  32.641337   35.460993   5000.000000
2017-05-25  0.000000    35.460993   5000.000000
2017-05-26  32.372936   35.460993   5000.000000
2017-05-29  32.372936   0.000000    10037.588652

And as you can see, my code takes into account the columns Facebook only I still don't understand why.

The result that I expect is this one :

             Apple      Facebook       cash
Date            
2017-05-19  0.000000    0.000000    10000.000000
2017-05-22  0.000000    0.000000    10000.000000
2017-05-23  32.641337   35.460993   0
2017-05-24  32.641337   35.460993   0
2017-05-25  0.000000    35.460993   5024.481
2017-05-26  32.372936   35.460993   0
2017-05-29  32.372936   0.000000    5037.58867

I don't have any problem if I only use one stock, but it became a bit difficult with two or more stocks and I would like to know what am I doing wrong.

If somebody has some time and an idea to solve this problem, you are welcome! Thanks

Aucun commentaire:

Enregistrer un commentaire