Share This Article:

Stock Future Implementation: CSI 300 Index Rebalance

Abstract Full-Text HTML XML Download Download as PDF (Size:975KB) PP. 1914-1945
DOI: 10.4236/me.2019.108123    50 Downloads   131 Views  
Author(s)    Leave a comment

ABSTRACT

In this essay, an investigation into the performance of Index Rebalancing strategy is explored. Specifically, the discussion is in the context of Shanghai-Shenzhen 300 Index (CSI 300), a Chinese equity index which replicates the performance of the top three hundred stocks in Shanghai-Shenzhen exchanges. When an index reconstitutes, it may result in significant buying power on the stocks which are added to the index and corresponding selling power on the stocks which are removed from the index. The strategy of Index Rebalancing thus takes advantages of the occurrence of price inefficiency. In evaluating the performance of Index Rebalancing on CSI 300, this essay will look into the profitability and volatility of the strategy referring to different benchmarks and taking consideration on how improvements of beta-portfolio, stop-loss, and maximum drawdown could bring change to the strategy performance. The information gathered and calculated has been analyzed to provide an overview of the overall performance of Index Rebalancing strategy on CSI 300. The out-of-sample test further outlines the performance of our Index Rebalancing strategy, in which a Win Ratio of 100% and the Sharpe Ratio and Information Ratio similar to in-sample ones imply the low risk of this strategy, while the lower average profit rate demonstrates limited profitability of the strategy. The investigation has led to the conclusion that as CSI 300 index retains a bearish trend, price inefficiencies after each index rebalance may not be significant enough to support highly profitable arbitrage. However, Index Rebalancing is still regarded as an advisable alternative investment strategy for the high Win Ratio and the low risk.

1. Introduction

With the outbreak of the trade war between China and the United States, the uncertainty of the Chinese stock market has been intensified, inducing more investors to explore alternative investment methods. Index Rebalancing is regarded as a powerful alternative investment strategy. Its mechanism is based on the arbitrage opportunity arising from short-term price inefficiencies of equities in the addition and deletion lists of the rebalancing index [1] , implying that investors could categorize stocks’ performance by the addition and deletion lists without manually estimating the trend for each stock.

Shanghai-Shenzhen 300 Index (CSI 300) is the most influential equity index in the Chinese market, which selects the top 300 stocks traded in Shanghai and Shenzhen stock exchanges. This index rebalances twice a year, more likely during the second or third Monday of June and the second or third Monday of December. Since constituents with excellent performance tend to possess high liquidity and large sizes, during each index rebalance, stocks which are eliminated from the index may undergo a downward trend, while the added stocks may undergo an upward trend. Therefore, investors could take short positions on the eliminated ones and take long positions on the added ones to gain profits. They could also estimate the purchases and sales of constituent stocks by tracking passive mutual funds and exchange-traded funds, hence to discover the arbitrage opportunities in trading constituent stocks.

In constructing the strategy portfolio, investors could apply the weight coefficients of stocks in the CSI 300. As the index decides weight coefficients based on the performance of shares, the existing portfolio will be the optimum choice to invest. And since weight coefficients also consider the volatility of stocks, investing that proportion can hedge the market risk for investors.

This investigation intends to explore the performance of conducting Index Rebalancing on CSI 300. For the strategy employing a dollar-neutral portfolio, the profit and loss will be calculated and analyzed at first. Improvements of applying beta-neutral portfolio, stop-loss, and maximum drawdown will then be discussed in the refinement, which will involve calculating the profit-loss for each trading period, annual profit rate, Win Ratio, Sharpe Ratio, and Information Ratio. During the investigation, difficulties and proposals of Index Rebalancing will also be explained. A conclusion will then be drawn based on the results of both the investigation and an out-of-sample test for the overall performance.

2. Specification

2.1. Universe

The universe is the stocks relevant to the CSI 300 Index, including those that are eliminated from or added to the CSI 300 Index during the two rebalances every year.

2.2. Data Range

After harvesting the rebalance data of the CSI 300 Index twice a year from June 2009 to Dec 2018, which are 20 groups of data in total, we set a rule that we only perform implementation of our strategy or utilize the data for researching if less than 10% of the entire index is influenced during the rebalance. If too many stocks are involved in the rebalancing, then this index will be proven as unstable for the high fluctuation, so we would not invest in it under such circumstances. Therefore, we abandoned the rebalancing data of June 2014 and June 2015, leaving us with 18 sets of data in total.

We calculated the first 13 sets of investment returns from June 2009 to June 2016, regarding as the in-sample data. The 5 sets of investment return from December 2016 to December 2018 regarding as the out-of-sample data to be estimated.

Consider the short-term nature of the strategy, for each of the 13 in-sample data set, we collected prices of each affected stock at the sixtieth day after the rebalancing day and used those data to calculate parameters including but not limited to PnL, Sharpe Ratio, and Information Ratio.

2.3. Data Sources

Rebalance lists of stocks come from the official website of China Securities Index Co. Ltd. [2] and The China Stock Market & Accounting Research Database [3] . Daily prices of each stock on the lists and their respective market values are collected from the database Yucezhe [4] .

2.4. Signal Generation

Investors should take a short position on all stocks which are eliminated from the index and take a long position on all stocks which are added to the index. In an equal market-capitalization weighted portfolio, the buying and selling signals are +mktcap and −mktcap respectively, summing up to zero.

2.5. Portfolio Construction

1) Trading frequency: Low. Since the CSI 300 Index rebalances only twice a year, investors can only trade twice a year, after each rebalancing date.

2) Sizing: In this research, the total investment for each index rebalance is set as ¥2,000,000, in which ¥1,000,000 for all stocks added in and ¥1,000,000 for all stocks being eliminated.

3) Hedging: Every time when the index is rebalanced, the weighting coefficients of stocks will be reset based on the size and liquidity of stocks. To reduce the market risk, dollar-neutral hedging can be applied in the portfolio construction to equate investment proportion of stocks in the addition and the elimination lists, as well as the weighting coefficients in the index. If the weighting coefficients of stocks are not given, we utilize the proportion of the stocks’ respective market capitalization. We may also include beta-neutral hedging in the refinement part if necessary.

2.6. Trade Execution

1) Cost: Transaction costs in this strategy are mainly consisting of broker commissions (0.37% in Shanghai and Shenzhen Stock Exchanges), stamp tax (0.10%) [5] , along with other components of levy fees, transfer fees, and spread the costs of which data are not readily accessible so are not considered in this investigation.

2) Profitability: As stocks possessing higher liquidity have relatively higher weight coefficients in the index, the dollar-neutral portfolio may perform well for high liquidity, increasing the possibility of profitable tradings.

3. Implementation

3.1. PnL Graph

Figure 1 is the accumulated Profit and Loss graph for the 13 trading periods.

The x-axis refers to trading days where one trading period equals 60 trading days (indicated by separating two trading periods with a horizontal segment). The y-axis refers to the total revenue when a total of ¥2,000,000 is invested in every trading period.

We can get from the figure that the accumulated PnL fluctuates a lot and remains at around 0 finally, which means that we probably won’t gain profit and the risk of this strategy is very high.

3.2. Statistics

This table (see Table 1) shows that in this condition, the profit ratio, the Sharpe ratio and the information ratio are all below zero, and the win ratio is below 50%. As a result, we need to carry on some refinements to ameliorate the strategy.

3.3. Difficulties

1) Difficulties in harvesting selective data

When we do research on this strategy, the percentage of how much each stock taking up in the index should be known for the investment rate in our portfolio. However, we could only find the list of stocks involved in the index for each time after rebalancing without the percentage of each stock. After knowing that the percentage of each stock in the index is calculated according to their liquidity and the volume of the parent company, we decided to use the market cap ratio as the proportion of each stock involved.

2) Difficulties in calculating the percentage of each stock

When we calculate the percentage of each stock in the portfolio, we find that sometimes a stock is out of the market (it’s market cap directly turns to 0.00) at the rebalance day (always eliminated ones), which means that we can’t manage to trade it. A possible explanation for this could be those companies being

Figure 1. Accumulated PnL for 13 trading periods.

Table 1. Statistics before refinements.

broken, which is why those stocks are eliminated from the index. In this case that stock takes up 0 in our portfolio, because that stock has no liquidity at that time as it was out of the market, and we cannot trade it.

There are also some cases that the stock was in the market at the rebalance day, but when we decide to close the position, we found that it came out of the market at some time during the period we are holding the position. In this case, we manage to close the position of that stock at the day before it came out of the market with all the other stocks in the normal condition.

4. Refinement

4.1. Implemented

1) Using beta to hedge

We can use “beta” to change the way we constitute our portfolio instead of same amount of investment. This means that the investment proportion of stocks being added or deleted are equal to the beta proportion of stocks in the index. We assume that the result of beta-neutral hedging will be better than that of dollar-neutral hedging as it takes beta into consideration which can significantly reduce market risk.

We also set the trading day range as 60 days, the accumulated PnL data is shown in the graph below with the result of this refinement.

We can get from this figure (see Figure 2) that though the accumulated PnL has been above 0 for most time, the final PnL is still very low. That means this refinement works but its effect is very poor, so we need further refinements.

It is notable that using beta hedging results in a generally more profitable outcome, including an increase in profit ratio, Sharpe Ratio, as well as Information ratio (Table 2).

Figure 2. Accumulated PnL after refinement (1).

Table 2. Statistics after refinement (1).

2) Changing day range

After establishing the superiority in profitability of beta hedging, we decide to implement all the other refinement exclusively based on beta hedging.

As presented in the PnL graph in refinement 1, in several circumstances, the value of the entire portfolio rises in the first several days but experiences a drop down afterwards, and this is the reason why the average profit ratio of our strategy is below zero. Therefore, we draw to the conclusion that the profitability of our strategy would improve if we change the trading day range shorter. Then we change the day range shorter to 10 trading days, 20 trading days and 40 trading days for testing. The result of our refinement is shown in the table below:

From the table above (see Table 3), it is obvious that the overall performance of closing the positions in 10 days is significantly better than the other three circumstances (as annual profit ratio, win ratio, Sharpe ratio and information ratio are all the highest among these four conditions), which are setting the time to close positions in the 20 trading days, 40 trading days or 60 trading days. However, the Sharpe ratio and the Information ratio is still not promising, so we still need to refine this strategy.

3) Adding two parameters

As revealed in the data above, although the annual average profit rate of two weeks condition is considerable and shows significant improvement compared to the original strategies, it still has a big fluctuation which causes the Sharpe ratio to be very low. In some cases, we find out that the investor either gain a significant fortune or suffer a great loss. In addition, this strategy is very inflexible,

Table 3. Statistics after refinement (2).

and we must close the position in the predetermined date and does not have any other parameter for any possible alterations. In order to improve this situation, we add two parameters, stop loss and max drawdown, to our strategy to reduce the risk and to profit better.

a) Stop-loss price

The first parameter is a stop-loss price. If the total value of the portfolio drops to a certain price, we would immediately close all positions and stop trading to avoid suffering more loss. During the research, due to the inadequate data of the stocks’ hourly prices, if the open price of a day is above the stop loss price and the close price of a day is below the stop-loss price, we consider that we should close the position at the moment the value reaches the stop-loss price (as we assume that the value changes successively). In addition, if both the open price and the close price are above the stop-loss price, but the lowest price is below the price, we will also close the position at the stop-loss price.

To find out the best values of this parameter, we can control variables. We have three different stop loss strategies at the percentages of 1%, 3%, 5%, which means that we cease to trade if the portfolio value drops to 99%, 97%, 95% of the previous value. The result of the research is shown below in the table (See Table 4).

We can see that among these three values, the condition of the 1% setting has the shortest day range, the highest profit ratio, win ratio, Sharpe ratio and Information Ratio. Therefore, we conclude that we should set stop loss at 1%.

b) Max drawdown

The second parameter is max drawdown. If the previous value of the portfolio is X0, and the value of the portfolio on the nth day after the first day is Xn, we set a variate named mp, mp = max{Xi − X0|1 ≤ i ≤ n}. If Xn − X0 < (1-max drawdown) * mp, we close the position as we think that the price dropped significantly from the summit price before, and it will keep dropping with very minimum possibility to come back up. Therefore, we close the position to ensure our profit. In this case, we can also manage to close the position at the moment that the value of the portfolio reaches the max drawdown value as it changes successively (as in the first circumstance).

To get the best value of max drawdown, we set stop loss at 1% then change max drawdown to see the result. We set max drawdown at 10%, 20%, 30%, 40%, 50% to look for the best parameter, and the result is shown below.

In the table (see Table 5) it is clearly shown that 30% and 40% are the two best values of this parameter. We finally think 30% is better because its average day range is shorter so it has lower risk.

Table 4. Statistics after adding stop loss.

Table 5. Statistics after using max drawdown.

In conclusion, the result shows that we should set the stop loss at 1% and the max drawdown at 30% for further refinement. This refinement improves the average profit ratio to 10.1452%, improves the Sharpe ratio to 1.0314 and improves the information ratio to 1.0732.

The graph below (see Figure 3) shows the accumulated PnL under this refinement (stop loss at 1% and max drawdown at 30%).

4.2. Proposals

1) Trading the eliminated ones and the added ones separately

In our strategy, we are always determined to invest the same amount of money in the eliminated stocks as well as added in stocks. However, the result of our data shows that the eliminated ones and the added ones have very different performances. With our research data, we can draw the conclusion that the eliminated stocks outperform the added ones.

We use the 10 days condition before refinement as an example. (The reason why we choose 10 days condition is that after the refinement, the average trading day period is 10.8 days, which is closest to 10 days). The data of the eliminated ones and the added ones is shown separately in the table above (see Table 6). We can easily find out that the eliminated stocks perform better in all these three parameters than the added ones.

As a result, further possible refinements of this strategy may include changing the proportion of the total investment ratio of the eliminated ones and the added ones. We may invest with different ratio of the eliminated stocks and the added ones (for example 2:1 or 3:1) while the eliminate stocks having a heavier weight.

2) Not using all stocks influenced during the rebalance

In our strategy, we invest in all the stocks involved in the rebalance list. However, we might invest more on the stocks that take up larger proportion in the

Figure 3. Accumulated PnL after all refinements.

Table 6. Statistics on eliminated ones and added ones.

index. We consider that for the stocks that take up a very small part of the index, they have small market cap and poor liquidity, thus may not be influenced as much by the change of the index. As a result, we can choose not to invest in those stocks to potentially lower the risk. We can achieve this through different methods, for example, we can always drop the five stocks on the rebalance list which takes the smallest proportion in the index; or, we can simply not to involve stocks with a market cap under a certain value in our strategy.

3) Involving data of the two abnormal rebalances

When we are harvesting data, there are two abnormal rebalance time of the CSI 300 index, which took place in June 2014 and June 2015. We drop these two data sets because we consider the index to be unstable at the time around the rebalancing, and we decide not to implement our strategy if more than 10% of the list was changed during one rebalance as we mentioned above. Nevertheless, we can still also calculate the data of those two data set to see the result, and then decide if we should stop investing in that condition or not.

5. Conclusions

5.1. Out of Sample Tests

We set 5 sets of out of sample data, from December 2016 to December 2018. After the research and refinement, we use our strategy with the following refinements: beta hedge, stop loss (1%) and max drawdown (30%) to test our strategy with out of sample data to find out the performance of our strategy. The data is shown in the table below with an accumulated PnL graph.

Table 7. Statistics for out-of-sample data.

Figure 4. Accumulated PnL for out-of-sample data.

5.2. Trading Recommendation

From the data above (see Table 7 and Figure 4), we could clearly see that under this strategy (with refinements), all five groups of out of sample data perform outstandingly. The win ratio is 100% with Sharpe Ratio and Information Ratio similar to the in-sample ones, which means that this strategy has a low risk.

On the other hand, the average profit ratio is only 2.8%, much lower than that of the in-sample ones. Also, we find that the Information ratio is significantly higher than the Sharpe ratio, which indicates that the price of this index has been dropping in recent years.

In conclusion, our research provides a practical trading strategy that can be used to generate profit with a rarely discussed index in a newly and rapidly developing financial market. The Chinese financial market is overlooked by majority of investors but it is rapidly developing, leaving investors with the potential of huge profits. Our research would provide significant insights and practical methods for those who want to seek opportunities to gain in this unsaturated market. Our strategy has a relatively low risk, but along with the bearish performance of the CSI 300 Index itself, investors may not be able to obtain a large amount of profit from this strategy. Consequently, we recommend those who have low risk tolerance to use our strategy, instead of those who are trying to make a significant profit in a short period of time.

Appendix

We used the following codes to calculate different parameters and values.

1) Percentage calculation

import csv

#kicked out ones

with open('沪深300调整名单.csv','r') as f1:

ff=csv.reader(f1)

lst=list(ff)

for j in range(0,len(lst)):

if lst[j][0]=='2016.06.13':#can be changed in different rebalance time

a=j

elif lst[j][0]=='2015.12.14':#can be changed in different rebalance time

b=j

time_range=b-a

f=''

for i in range(0,time_range):

f=f+'0'

f=list(f)

for k in range(0,time_range):

f[k]=lst[k+a][1]

f[k]='trading-data.20190211/stock data/'+f[k]+'.csv'

m=f

for i in range(0,time_range):

with open(f[i],'r') as fff:

fffpie=list(csv.reader(fff))

for j in range(0,len(fffpie)):

if fffpie[j][1]=='2016-06-13' or fffpie[j][1]=='2016/06/13':#can be changed in different rebalance time

m[i]=fffpie[j][10]

m[i]=float(m[i])

for i in range(0,time_range):

if type(m[i])!=float:

m[i]=0

print(len(m))

sum=0

for i in range(0,time_range):

sum=sum+m[i]

for j in range(0,time_range):

m[j]=m[j]/sum

print(m[j])

print(' ')

print(' ')

print(' ')

#added in ones

g=f

for k in range(0,time_range):

g[k]=lst[k+a][4]

g[k]='trading-data.20190211/stock data/'+g[k]+'.csv'

for i in range(0,time_range):

with open(g[i],'r') as ggg:

gggpie=list(csv.reader(ggg))

for j in range(0,len(gggpie)):

if gggpie[j][1]=='2016-06-13' or gggpie[j][1]=='2016/06/13':#can be changed in different rebalance time

m[i]=gggpie[j][10]

m[i]=float(m[i])

for i in range(0,time_range):

if type(m[i])!=float:

m[i]=0

sum=0

for i in range(0,time_range):

sum=sum+m[i]

for j in range(0,time_range):

m[j]=m[j]/sum

print(m[j])

2)Beta calculation

import csv

with open('沪深300调整名单.csv','r') as f1:

ff=csv.reader(f1)

lst=list(ff)

for j in range(0,len(lst)):

if lst[j][0]=='2016.06.13':#can be changed in different rebalance time

a=j

elif lst[j][0]=='2015.12.14':#can be changed in different rebalance time

b=j

num=b-a

f=''

for i in range(0,num):

f=f+'0'

f=list(f)

#kicked out ones

for k in range(0,num):

f[k]=lst[k+a][1]

f[k]='trading-data.20190211/stock data/'+f[k]+'.csv'

#calculate profit rate of a certain stock

for unuse in range(0,num):

with open(f[unuse], 'r')as ff:

data=csv.reader(ff)

datal=list(data)

start_day=0

end_day=0

for a1 in range(0,len(datal)):

if datal[a1][1]=='2015-12-31':#can be changed in different rebalance time

end_day=a1

for a2 in range(0,len(datal)):

if datal[a2][1]=='2015-01-02':#can be changed in different rebalance time

start_day=a2

if end_day==0:

for l in range(0,len(datal)):

if datal[l][1][0:4]=='2015':#can be changed in different rebalance time

end_day=l

break

if start_day==0:

for l in range(end_day,len(datal)):

if datal[l][1][0:4]!='2015':#can be changed in different rebalance time

start_day=l-1

break

if datal[len(datal)-1][1][0:4]==datal[end_day][1][0:4]:

start_day=len(datal)-2

s=0

for i in range(0,len(datal)):

if datal[i][1][0:4]=='2015':s=s+1#can be changed in different rebalance time

if s==0:

end_day=1

for j in range(1,len(datal)):

if datal[j][1][0:4]==datal[1][1][0:4]:

start_day=start_day+1

time_range=start_day-end_day+1

qi=float(datal[start_day+1][5])

flt=''

for i in range(0,time_range):

pi=datal[i+end_day][5]

pi=float(pi)

per=(pi-qi)/qi

perc=str(per)

flt=flt+perc+','

qi=pi

per=flt.split(',')

del per[len(per)-1]

for i in range(0,time_range):

per[i]=float(per[i])

#data of no risk profit rate

with open('沪深300收益率.csv','r')as fi:

data_index=csv.reader(fi)

datai=list(data_index)

flt1=flt

flt2=flt

flt3=flt

no_risk_rate=flt1.split(',')

del no_risk_rate[len(no_risk_rate)-1]

for j in range(1,len(datai)):

if datai[j][0]==datal[end_day][1]:

start=j

for k in range(0,time_range):

no_risk_rate[k]=datai[start+k][3]

no_risk_rate[k]=float(no_risk_rate[k])

extra_return_stock=flt2.split(",")

del extra_return_stock[len(extra_return_stock)-1]

#rm-rf of the stock

for l in range(0,time_range):

extra_return_stock[l]=per[l]-no_risk_rate[l]

#rm-rf of the whole index

extra_return_index=flt3.split(',')

del extra_return_index[len(extra_return_index)-1]

for m in range(0,time_range):

extra_return_index[m]=datai[start+m][4]

extra_return_index[m]=float(extra_return_index[m])

#calculate beta

sum_i=0

sum_s=0

for i in range(0,time_range):

sum_i=sum_i+extra_return_index[i]

xbar=sum_i/time_range

for j in range(0,time_range):

sum_s=sum_s+extra_return_stock[i]

ybar=sum_s/time_range

VAR=0

COV=0

for i in range(0,time_range):

VAR=VAR+(extra_return_index[i]-xbar)*(extra_return_index[i]-xbar)

var=VAR/(time_range-1)

for j in range(0,time_range):

COV=COV+(extra_return_index[j]-xbar)*(extra_return_stock[j]-ybar)

cov=COV/(time_range-1)

beta=cov/var

print(beta)

print(' ')

print(' ')

print(' ')

#added in ones

for k in range(0,num):

f[k]=lst[k+a][4]

f[k]='trading-data.20190211/stock data/'+f[k]+'.csv'

for unuse in range(0,num):

with open(f[unuse], 'r')as ff:

data=csv.reader(ff)

datal=list(data)

start_day=0

end_day=0

for a1 in range(0,len(datal)):

if datal[a1][1]=='2016-06-13':#can be changed in different rebalance time

end_day=a1

for a2 in range(0,len(datal)):

if datal[a2][1]=='2015-12-14':#can be changed in different rebalance time

start_day=a2

if end_day==0:

for l in range(0,len(datal)):

if datal[l][1][0:4]=='2015':#can be changed in different rebalance time

end_day=l

break

if start_day==0:

for l in range(end_day,len(datal)):

if datal[l][1][0:4]!='2015':#can be changed in different rebalance time

start_day=l-1

break

if datal[len(datal)-1][1][0:4]==datal[end_day][1][0:4]:

start_day=len(datal)-2

s=0

for i in range(0,len(datal)):

if datal[i][1][0:4]=='2015':s=s+1#can be changed in different rebalance time

if s==0:

end_day=1

for j in range(1,len(datal)):

if datal[j][1][0:4]==datal[1][1][0:4]:

start_day=start_day+1

time_range=start_day-end_day+1

qi=float(datal[start_day+1][5])

flt=''

for i in range(0,time_range):

pi=datal[i+end_day][5]

pi=float(pi)

per=(pi-qi)/qi

perc=str(per)

flt=flt+perc+','

qi=pi

per=flt.split(',')

del per[len(per)-1]

for i in range(0,time_range):

per[i]=float(per[i])

#data of no risk profit rate

with open('沪深300收益率.csv','r')as fi:

data_index=csv.reader(fi)

datai=list(data_index)

flt1=flt

flt2=flt

flt3=flt

no_risk_rate=flt1.split(',')

del no_risk_rate[len(no_risk_rate)-1]

for j in range(1,len(datai)):

if datai[j][0]==datal[end_day][1]:

start=j

for k in range(0,time_range):

no_risk_rate[k]=datai[start+k][3]

no_risk_rate[k]=float(no_risk_rate[k])

extra_return_stock=flt2.split(",")

del extra_return_stock[len(extra_return_stock)-1]

#rm-rf of the stock

for l in range(0,time_range):

extra_return_stock[l]=per[l]-no_risk_rate[l]

#rm-rf of the whole index

extra_return_index=flt3.split(',')

del extra_return_index[len(extra_return_index)-1]

for m in range(0,time_range):

extra_return_index[m]=datai[start+m][4]

extra_return_index[m]=float(extra_return_index[m])

#calculate beta

sum_i=0

sum_s=0

for i in range(0,time_range):

sum_i=sum_i+extra_return_index[i]

xbar=sum_i/time_range

for j in range(0,time_range):

sum_s=sum_s+extra_return_stock[i]

ybar=sum_s/time_range

VAR=0

COV=0

for i in range(0,time_range):

VAR=VAR+(extra_return_index[i]-xbar)*(extra_return_index[i]-xbar)

var=VAR/(time_range-1)

for j in range(0,time_range):

COV=COV+(extra_return_index[j]-xbar)*(extra_return_stock[j]-ybar)

cov=COV/(time_range-1)

beta=cov/var

print(beta)

3) PnL calculation

import csv

with open('沪深300调整名单.csv','r') as f1:

ff=csv.reader(f1)

fff=list(ff)

for j in range(0,len(fff)):

if fff[j][0]=='2016.06.13':#can be changed in different rebalance times

a=j

elif fff[j][0]=='2015.12.14':#can be changed in different rebalance times

b=j

num=b-a

#1,kicked out ones

f=''

for i in range(0,num):

f=f+' '

f=list(f)

for i in range(0,num):

f[i]=fff[a+i][1]

f[i]='trading-data.20190211/stock data/'+f[i]+'.csv'

invest_amount=1000000

with open('沪深300每日价格.csv','r') as d:

da=csv.reader(d)

data_i=list(da)

for j in range(0,len(data_i)):

if data_i[j][0]==fff[a][0].replace('.','-') or data_i[j][0]==fff[a][0].replace('.','/').replace('06','6'):

begin=j

pro=''

for leng in range(0,61):

pro=pro+'0'

pro=list(pro)

for leng in range(0,61):

pro[leng]=float(pro[leng])

for i in range(0,num):

if float(fff[a+i][2].strip('%'))==0:

continue

with open(f[i],'r') as s:

st=csv.reader(s)

stock=list(st)

for j in range(0,len(stock)):

if stock[j][1]==fff[a][0].replace('.','-') or stock[j][1]==fff[a][0].replace('.','/').replace('06','6'):

start_day=j

for k in range(0,61):

if start_day-k==0:continue

pro[k]=pro[k] + (float(stock[start_day][2]) − float(stock[start_day-k][2]))/float(stock[start_day][2]) * float(fff[a + i][2].strip('%'))/100 * invest_amount

rate=0

for k in range(0,num):

rate = rate + float(fff[a + k][2].strip('%')) / 100 * float(fff[a + k][3])

for k in range(0,61):

pro[k]=pro[k]+invest_amount*rate/float(data_i[begin][6])*(float(data_i[begin-k][6])-float(data_i[begin][6]))

#2

g=''

for i in range(0,num):

g=g+' '

g=list(g)

pro1=''

for leng in range(0,61):

pro1=pro1+'0'

pro1=list(pro1)

for leng in range(0,61):

pro1[leng]=float(pro1[leng])

for i in range(0,num):

g[i]=fff[a+i][4]

g[i]='trading-data.20190211/stock data/'+g[i]+'.csv'

for i in range(0,num):

if float(fff[a+i][2].strip('%'))==0:

continue

with open(g[i],'r') as ss:

sst=csv.reader(ss)

stock=list(sst)

for j in range(0,len(stock)):

if stock[j][1]==fff[a][0].replace('.','-') or stock[j][1]==fff[a][0].replace('.','/').replace('06','6'):

start_day=j

for k in range(0,61):

pro1[k]=pro1[k] + (float(stock[start_day-k][2]) − float(stock[start_day][2]))/float(stock[start_day][2]) * float(fff[a + i][5].strip('%'))/100 * invest_amount

rate1=0

for k in range(0,num):

rate1 = rate1 + float(fff[a + k][5].strip('%')) / 100 * float(fff[a + k][6])

for k in range(0,61):

pro1[k]=pro1[k]+invest_amount*rate1/float(data_i[begin][6])*(float(data_i[begin][6])-float(data_i[begin-k][6]))

for k in range(0,61):

print(pro[k]+pro1[k])

4)main codes of beta hedge (before refinement)

import csv

with open('沪深300调整名单.csv','r') as f1:

ff=csv.reader(f1)

fff=list(ff)

for j in range(0,len(fff)):

if fff[j][0]=='2016.06.13':#can be changed in different rebalance times

a=j

elif fff[j][0]=='2015.12.14':#can be changed in different rebalance times

b=j

num=b-a

#1,kicked out ones

f=''

for i in range(0,num):

f=f+' '

f=list(f)

for i in range(0,num):

f[i]=fff[a+i][1]

f[i]='trading-data.20190211/stock data/'+f[i]+'.csv'

pro1=pro2=pro3=pro4=0

invest_amount=1000000 #We can assume the amount of money that we invest in this strategy.

print('Money invested:'+str(invest_amount))

for i in range(0,num):

if float(fff[a+i][2].strip('%'))==0:

continue

with open(f[i],'r') as s:

st=csv.reader(s)

stock=list(st)

for j in range(0,len(stock)):

if stock[j][1]==fff[a][0].replace('.','-') or stock[j][1]==fff[a][0].replace('.','/').replace('06','6'):

start_day=j

trade_time1=start_day-10 #two weeks

trade_time2=start_day-20 #one month

trade_time3=start_day-40 #two months

trade_time4=start_day-60 #three months

pro1=pro1+(float(stock[start_day][2])-float(stock[trade_time1][2]))/float(stock[start_day][2])*float(fff[a+i][2].strip('%'))/100*invest_amount

pro2=pro2+(float(stock[start_day][2])-float(stock[trade_time2][2]))/float(stock[start_day][2])*float(fff[a+i][2].strip('%'))/100*invest_amount

pro3=pro3+(float(stock[start_day][2])-float(stock[trade_time3][2]))/float(stock[start_day][2])*float(fff[a+i][2].strip('%'))/100*invest_amount

pro4=pro4+(float(stock[start_day][2])-float(stock[trade_time4][2]))/float(stock[start_day][2])*float(fff[a+i][2].strip('%'))/100*invest_amount

with open('沪深300每日价格.csv','r') as d:

da=csv.reader(d)

data_i=list(da)

for j in range(0,len(data_i)):

if data_i[j][0]==fff[a][0].replace('.','-') or data_i[j][0]==fff[a][0].replace('.','/').replace('06','6'):

begin=j

trading_time1=begin-10

trading_time2=begin-20

trading_time3=begin-40

trading_time4=begin-60

rate=0

for k in range(0,num):

rate=rate+float(fff[a+k][2].strip('%'))/100*float(fff[a+k][3])

pro1_index=invest_amount*rate/float(data_i[begin][6])*(float(data_i[trading_time1][6])-float(data_i[begin][6]))

pro2_index=invest_amount*rate/float(data_i[begin][6])*(float(data_i[trading_time2][6])-float(data_i[begin][6]))

pro3_index=invest_amount*rate/float(data_i[begin][6])*(float(data_i[trading_time3][6])-float(data_i[begin][6]))

pro4_index=invest_amount*rate/float(data_i[begin][6])*(float(data_i[trading_time4][6])-float(data_i[begin][6]))

#whole pnl for kicked out ones

pro1_out=pro1+pro1_index

pro2_out=pro2+pro2_index

pro3_out=pro3+pro3_index

pro4_out=pro4+pro4_index

print('Kicked out ones:')

print(str(pro1_out))

print(str(pro2_out))

print(str(pro3_out))

print(str(pro4_out))

print(' ')

print(' ')

#2,added in ones

g=''

for i in range(0,num):

g=g+' '

g=list(g)

for i in range(0,num):

g[i]=fff[a+i][4]

g[i]='trading-data.20190211/stock data/'+g[i]+'.csv'

pro1_stock=pro2_stock=pro3_stock=pro4_stock=0

for i in range(0,num):

if float(fff[a+i][2].strip('%'))==0:

continue

with open(g[i],'r') as s:

st=csv.reader(s)

stock=list(st)

for j in range(0,len(stock)):

if stock[j][1]==fff[a][0].replace('.','-') or stock[j][1]==fff[a][0].replace('.','/').replace('06','6'):

start_day=j

trade_time1=start_day-10 #two weeks

trade_time2=start_day-20 #one month

trade_time3=start_day-40 #two months

trade_time4=start_day-60 #three months

pro1_stock=pro1_stock+(float(stock[trade_time1][2])-float(stock[start_day][2]))/float(stock[start_day][2])*float(fff[a+i][5].strip('%'))/100*invest_amount

pro2_stock=pro2_stock+(float(stock[trade_time2][2])-float(stock[start_day][2]))/float(stock[start_day][2])*float(fff[a+i][5].strip('%'))/100*invest_amount

pro3_stock=pro3_stock+(float(stock[trade_time3][2])-float(stock[start_day][2]))/float(stock[start_day][2])*float(fff[a+i][5].strip('%'))/100*invest_amount

pro4_stock=pro4_stock+(float(stock[trade_time4][2])-float(stock[start_day][2]))/float(stock[start_day][2])*float(fff[a+i][5].strip('%'))/100*invest_amount

rate2=0

for j in range(0,num):

rate2=rate2+float(fff[a+j][5].strip('%'))/100*float(fff[a+j][6])

pro1_index=invest_amount*rate2/float(data_i[begin][6])*(float(data_i[begin][6])-float(data_i[trading_time1][6]))

pro2_index=invest_amount*rate2/float(data_i[begin][6])*(float(data_i[begin][6])-float(data_i[trading_time2][6]))

pro3_index=invest_amount*rate2/float(data_i[begin][6])*(float(data_i[begin][6])-float(data_i[trading_time3][6]))

pro4_index=invest_amount*rate2/float(data_i[begin][6])*(float(data_i[begin][6])-float(data_i[trading_time4][6]))

pro1_in=pro1_stock+pro1_index

pro2_in=pro2_stock+pro2_index

pro3_in=pro3_stock+pro3_index

pro4_in=pro4_stock+pro1_index

print('Added in ones:')

print(str(pro1_in))

print(str(pro2_in))

print(str(pro3_in))

print(str(pro4_in))

print(' ')

print(' ')

print('Whole condition:')

print(str(pro1_in+pro1_out))

print(str(pro2_in+pro2_out))

print(str(pro3_in+pro3_out))

5) Codes related with Information ratio

import csv

with open('沪深300每日价格.csv','r') as file:

f=csv.reader(file)

ff=list(f)

with open('沪深300调整名单.csv','r')as gi:

g=csv.reader(gi)

gg=list(g)

st=''

for i in range(0,19):

st=st+' '

st=list(st)

m=0

for i in range(0,len(gg)):

if gg[i][0]!='':

st[m]=gg[i][0]

m=m+1

if m==19:break

for i in range(1,14):

st[i-1]=st[i+5]

ir=''

for i in range(0,13):

ir=ir+' '

ir=list(ir)

for i in range(0,13):

ir[i]=0

k=0

for i in range(0,len(ff)):

if ff[i][0]==st[k].replace('.','-') or ff[i][0]==st[k].replace('.','/').replace('06','6'):

start=i

sp=float(ff[i][6])

ep=float(ff[i-60][6])#The number 60 can be changed if time range changes

ir[k]=(ep-sp)/sp

k=k+1

for i in range(0,13):

6) Beta hedge codes after refinements

import csv

with open('沪深300调整名单.csv','r') as f1:

ff=csv.reader(f1)

fff=list(ff)

for j in range(0,len(fff)):

if fff[j][0]=='2016.06.13':#can be changed in different rebalance times

a=j

elif fff[j][0]=='2015.12.14':#can be changed in different rebalance times

b=j

num=b-a

#1,kicked out ones

f=''

for i in range(0,num):

f=f+' '

f=list(f)

for i in range(0,num):

f[i]=fff[a+i][1]

f[i]='trading-data.20190211/stock data/'+f[i]+'.csv'

invest_amount=1000000

with open('沪深300每日价格.csv','r') as d:

da=csv.reader(d)

data_i=list(da)

for j in range(0,len(data_i)):

if data_i[j][0]==fff[a][0].replace('.','-') or data_i[j][0]==fff[a][0].replace('.','/').replace('06','6'):

begin=j

pro=''

pri=pro

for leng in range(0,61):

pro=pro+'0'

pri=pri+'0'

pro=list(pro)

pri=list(pri)

for leng in range(0,61):

pro[leng]=float(pro[leng])

pri[leng]=float(pri[leng])

for i in range(0,num):

if float(fff[a+i][2].strip('%'))==0:

continue

with open(f[i],'r') as s:

st=csv.reader(s)

stock=list(st)

for j in range(0,len(stock)):

if stock[j][1]==fff[a][0].replace('.','-') or stock[j][1]==fff[a][0].replace('.','/').replace('06','6'):

start_day=j

for k in range(0,61):

if start_day-k==0:continue

pro[k]=pro[k] + (float(stock[start_day][2]) - float(stock[start_day-k][2]))/float(stock[start_day][2]) * float(fff[a + i][2].strip('%')) / 100 * invest_amount

rate=0

for k in range(0,num):

rate = rate + float(fff[a + k][2].strip('%')) / 100 * float(fff[a + k][3])

for k in range(0,61):

pro[k]=pro[k]+invest_amount*rate/float(data_i[begin][6])*(float(data_i[begin-k][6])-float(data_i[begin][6]))

for k in range(0,61):

pri[k]=invest_amount+pro[k]

max=invest_amount

end_day=0

for k in range(0,61):

if max

if (pro[k]<(max-invest_amount)*0.7 and max>invest_amount) or pri[k]

end_day=k

if pro[k]<(max-invest_amount)*0.7 and max>invest_amount:

pro[k]=(max-invest_amount)*0.7

if pro[k]<-0.01*invest_amount and max-invest_amount==0:

pro[k]=-0.01*invest_amount

break

for k in range(end_day+1,61):

pri[k]=0

pro[k]=0

for k in range(1,end_day+1):

print(pro[k])

print(end_day)

print(' ')

print(' ')

#2,added in ones

g=''

for i in range(0,num):

g=g+' '

g=list(g)

pro1=''

pri1=pro1

for leng in range(0,61):

pro1=pro1+'0'

pri1=pri1+'0'

pro1=list(pro1)

pri1=list(pri1)

for leng in range(0,61):

pro1[leng]=float(pro1[leng])

pri1[leng]=float(pri1[leng])

for i in range(0,num):

g[i]=fff[a+i][4]

g[i]='trading-data.20190211/stock data/'+g[i]+'.csv'

for i in range(0,num):

if float(fff[a+i][2].strip('%'))==0:

continue

with open(g[i],'r') as ss:

sst=csv.reader(ss)

stock=list(sst)

for j in range(0,len(stock)):

if stock[j][1]==fff[a][0].replace('.','-') or stock[j][1]==fff[a][0].replace('.','/').replace('06','6'):

start_day=j

for k in range(0,61):

pro1[k]=pro1[k] + (float(stock[start_day-k][2]) - float(stock[start_day][2]))/float(stock[start_day][2]) * float(fff[a + i][5].strip('%'))/100 * invest_amount

rate1=0

for k in range(0,num):

rate1 = rate1 + float(fff[a + k][5].strip('%')) / 100 * float(fff[a + k][6])

for k in range(0,61):

pro1[k]=pro1[k]+invest_amount*rate1/float(data_i[begin][6])*(float(data_i[begin-k][6])-float(data_i[begin][6]))

for k in range(0,61):

pri1[k]=invest_amount+pro1[k]

max1=invest_amount

end_day1=0

for k in range(0,61):

if max1

if (pro1[k]<(max1-invest_amount)*0.7 and max1>invest_amount) or pri1[k]

end_day1=k

if pro1[k]<(max1-invest_amount)*0.7 and max1>invest_amount:

pro1[k]=(max1-invest_amount)*0.7

if pro1[k]<(-0.01*invest_amount) and max1-invest_amount==0:

pro1[k]=(-0.01*invest_amount)

break

for k in range(end_day1+1,61):

pri1[k]=0

pro1[k]=0

for k in range(1,end_day1+1):

print(pro1[k])

7)Dollar Neutral Calculation

money = 10000

import csv

import os

datedate = '2014-12-15'

ls = 1 # long or short: long = 1 short = -1

"""

s1 = open('1.csv','r')

s1read = csv.reader(s1)

ss1 = list(s1read)

"""

menu = os.listdir("D:/stock_data")

s1 = open('SH_SZ_data.csv','r')

s1read = csv.reader(s1)

reb_data = list(s1read)

title = ['sz','sh']

eliminated_list = []

added_list = []

first = 180

last = 200

number = 20

for s in range(0,number): # change num 2 for total stock num

eliminated_list.append(0)

added_list.append(0)

s_count = - 1

for m in reb_data[first:last]: #form elimination stock list a,b a-1 b = b

s_count = s_count + 1

if m[0][0] == '0' or m[0][0] == '3':

eliminated_list[s_count] = title[0] + m[0] + '.csv'

elif m[0][0] == '6' :

eliminated_list[s_count] = title[1] + m[0] + '.csv'

a_count = - 1

for m in reb_data[first:last] : #form elimination stock list

a_count = a_count + 1

if m[1][0] == '0' or m[1][0] == '3':

added_list[a_count] = title[0] + m[1] + '.csv'

elif m[1][0] == '6':

added_list[a_count] = title[1] + m[1] + '.csv'

e_stock_list = []

a_stock_list = []

for s in range(0,number): # change num 2 for total stock num

e_stock_list.append(0)

a_stock_list.append(0)

count = -1

for data in eliminated_list:

count = count +1

e_stock_list[count] = list(csv.reader(open(data,'r')))

count = -1

for data in added_list:

count = count +1

a_stock_list[count] = list(csv.reader(open(data,'r')))

rebp_e = 0 # rebalance day price

rebp_a = 0

tmval_e = 0 # total market value

tmval_a = 0

a_output = {}

e_output = {}

# trade days

# rebalance: 60

# 1w: 55

# 2w: 50

# 1m: 40

# 2m: 20

# 3m: 0

for s in range(1,62):

a_output[s] = float(0)

e_output[s] = float(0)

for k in e_stock_list: # calculate total market value

for n in k:

if n[1] == datedate:

tmval_e = tmval_e + float(n[10])

for k in a_stock_list: # calculate total market value

for n in k:

if n[1] == datedate:

tmval_a = tmval_a + float(n[10])

for k in e_stock_list: # for stock in list

for f in k: # for date in stock

if f[1] == datedate:

rebp = float(f[2])

weight = float(f[10])

datepoint = k.index(f)

num = weight / tmval_e * money / rebp # number of individual stoc invested

c = 1 # date indication

for x in k[ datepoint -60 : datepoint ]: # for date in stock[1197:1257]

a = float(x[2])

e_output[c] = e_output[c] + (ls * (a - rebp) * num)

c = c+1

for k in a_stock_list: # for stock in list

for f in k: # for date in stock

if f[1] == datedate:

rebp = float(f[2])

weight = float(f[10])

datepoint = k.index(f)

num = weight / tmval_a * money / rebp # number of individual stoc invested

c = 1 #date indication

for h in k:

if h[1] == datedate:

datepoint = k.index(h)

print(float( k[datepoint][2]) - float(k[datepoint-5][2]) ) # To doublecheck abnormal data

for x in k[ datepoint -60 : datepoint ]: # for date in stock[1197:1257]

a = float(x[2])

a_output[c] = a_output[c] + (ls * (a - rebp) * num)

c = c+1

op_a = [q for q in a_output.values()]

op_e = [v for v in e_output.values()]

print()

print(datedate, ',long',',short',',total')

print('rebalance day, ', op_a[60]/100,',', op_e[60]/100,',',op_a[60]/100 - op_e[60]/100)

print('one week, ', op_a[55]/100,',',op_e[55]/100,',', op_a[55]/100-op_e[55]/100)

print('two weeks, ', op_a[50]/100,',',op_e[50]/100,',', op_a[50]/100 - op_e[50]/100)

print('one month, ', op_a[40]/100,',',op_e[40]/100,',', op_a[40]/100 - op_e[40]/100)

print('two month, ', op_a[20]/100,',',op_e[20]/100,',', op_a[20]/100 - op_e[20]/100)

print('three month, ', op_a[0]/100,',', op_e[0]/100,',', op_a[0]/100 - op_e[0]/100)

print('long,','short,')

print(op_a)

print(op_e)

print('0,0')

NOTES

*These authors (listed according to alphabetical order of first name) contributed to this work equally.

Conflicts of Interest

The authors declare no conflicts of interest regarding the publication of this paper.

Cite this paper

Wang, H. , Guo, P. and Wang, Y. (2019) Stock Future Implementation: CSI 300 Index Rebalance. Modern Economy, 10, 1914-1945. doi: 10.4236/me.2019.108123.

References

[1] Tagliani, M. (2009) The Practical Guide to Wall Street: Equities and Derivatives. John Wiley & Sons, Hoboken, 151-152.
https://doi.org/10.1002/9781118267820
[2] China Securities Index (2019) Index Data—China Securities Index Co., Ltd.
http://www.csindex.com.cn/en/downloads/indices?lb=All&xl=1
[3] Gtarsc.com. (2019) Guo Tai an Data Servicing Centre. http://www.gtarsc.com/Home
[4] Yucezhe.com. (2019) Stock Prices Prediction Using Historical Prices & Data.
https://www.yucezhe.com/product?name=overview
[5] Monex Boom Securities (2019) Stocks Trading Fees Schedule. http://boom.com./en/
https://www.boom.com/en/customer_service/fee_and_charges/
online_trading_commission_fees/

  
comments powered by Disqus

Copyright © 2018 by authors and Scientific Research Publishing Inc.

Creative Commons License

This work and the related PDF file are licensed under a Creative Commons Attribution 4.0 International License.