楼主: Dear_Li
1818 3

[程序分享] 股市风起云涌,我用Python分析周期之道 [推广有奖]

  • 0关注
  • 14粉丝

等待验证会员

已卖:405份资源

博士生

64%

还不是VIP/贵宾

-

威望
0
论坛币
699 个
通用积分
7.9246
学术水平
12 点
热心指数
16 点
信用等级
2 点
经验
4905 点
帖子
186
精华
0
在线时间
246 小时
注册时间
2018-7-21
最后登录
2019-1-16

楼主
Dear_Li 发表于 2018-10-16 11:11:35 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币
正文

股票市场周期是股票市场长期的价格模式,通常与商业周期有关。 它是技术分析的关键,其中投资方法基于周期或重复的价格模式。 如果我们对股市周期有了更好的理解,我们总能以相对低的价格买入并在每个周期以相对较高的价格卖出,将始终获得正的回报。当然,股票市场没有什么策略可以永远赚钱,但我们基于Python,可以帮助我们更深入、快速地了解隐藏在股市中的周期。


fbprophet简介

Fbprophet是Facebook发布的一个开源软件,旨在为大规模预测提供一些有用的指导。 默认情况下,它会将时间序列划分为趋势和季节性,可能包含年度,周度和每日。 但是,分析师可以定义自己的季节性。 为了更好地理解该库,先导文件是非常有用的。


该库的一个特点是简单性、灵活性。 由于我们想要计算的股票市场周期不限于每年,每周或每日,我们应该定义自己的周期,找出哪些更适合数据。 此外,由于周末没有交易,我们不应该使用每周季节性。 我们还可以通过addseasonality函数定义'selfdefine_cycle'。 所有设置只需两行代码即可完成。


  1. m = Prophet(weekly_seasonality=False,yearly_seasonality=False)
  2. m.add_seasonality('self_define_cycle',period=8,fourier_order=8,mode='additive')
复制代码

以Costco为例

我们可以使用Costco标的从2015/10/1到2018/10/1, 使用pandas_datareader,我们可以快速读取股票价格。如下图:

地址:https://pandas-datareader.readth ... st/remote_data.html


在下图中,我们可以看到从2015年开始有一个强劲的价格增长趋势。然而,在中途仍然存在很多上下周期波动,这些周期都是我们的赚钱点。

  1. ticker = "COST"
  2. start_date = '2015-10-01'
  3. end_date = '2018-10-01'
  4. stock_data = data.DataReader(ticker, 'iex', start_date, end_date)
  5. stock_data['close'].plot(figsize=(16,8),color='#002699',alpha=0.8)
  6. plt.xlabel("Date",fontsize=12,fontweight='bold',color='gray')
  7. plt.ylabel('Price',fontsize=12,fontweight='bold',color='gray')
  8. plt.title("Stock price for Costco",fontsize=18)
  9. plt.show()
复制代码


对于预测模型,评估它们的一种方法是样本均方误差。 我们可以使用2015/10/1至2018/3/31进行训练,并保留最后6个月的数据进行测试和计算样本均方误差。 在每个周期内,我们可以通过以最低价格买入并以最高价格卖出的方式来优化我们的回报。 为了简化过程,我们使用自定义函数cycle_analysis。 输出是一个列表,其中包含每个周期的预计回报和样本均方误差。

  • data:带有时间索引的Pandas数据
  • split_date:分割训练和测试数据的日期cycle:每个周期的间隔(天)
  • cycle:每个周期的间隔(天)
  • mode:季节性的加法或乘法(可选)
  • forecast_plot:是否打印预测图(可选,默认为False)
  • print_ind:是否打印每个周期的预计回报和是否采样均方误差(可选,默认为False)

  1. def cycle_analysis(data,split_date,cycle,mode='additive',forecast_plot = False,print_ind=False):
  2.    training = data[:split_date].iloc[:-1,]
  3.    testing = data[split_date:]
  4.    predict_period = len(pd.date_range(split_date,max(data.index)))
  5.    df = training.reset_index()
  6.    df.columns = ['ds','y']
  7.    m = Prophet(weekly_seasonality=False,yearly_seasonality=False,daily_seasonality=False)
  8.    m.add_seasonality('self_define_cycle',period=cycle,fourier_order=8,mode=mode)
  9.    m.fit(df)
  10.    future = m.make_future_dataframe(periods=predict_period)
  11.    forecast = m.predict(future)
  12.    if forecast_plot:
  13.        m.plot(forecast)
  14.        plt.plot(testing.index,testing.values,'.',color='#ff3333',alpha=0.6)
  15.        plt.xlabel('Date',fontsize=12,fontweight='bold',color='gray')
  16.        plt.ylabel('Price',fontsize=12,fontweight='bold',color='gray')
  17.        plt.show()
  18.    ret = max(forecast.self_define_cycle)-min(forecast.self_define_cycle)
  19.    model_tb = forecast['yhat']
  20.    model_tb.index = forecast['ds'].map(lambda x:x.strftime("%Y-%m-%d"))
  21.    out_tb = pd.concat([testing,model_tb],axis=1)
  22.    out_tb = out_tb[~out_tb.iloc[:,0].isnull()]
  23.    out_tb = out_tb[~out_tb.iloc[:,1].isnull()]
  24.    mse = mean_squared_error(out_tb.iloc[:,0],out_tb.iloc[:,1])
  25.    rep = [ret,mse]
  26.    if print_ind:
  27.        print "Projected return per cycle: {}".format(round(rep[0],2))
  28.        print "MSE: {}".format(round(rep[1],4))
  29.    return rep
复制代码


在下面两个图中,我们将两种不同cycle(30和300)分别应用于Costco股票价格,并将2018/4/1作为训练和测试的分割日期。 正如我们所看到的,如果我们选择一个较短的长度(例如30天),则一个周期内的回报是很小的,我们需要经常进行交易,如果我们选择较长的长度,它会延长我们的预测(例如300天)。




我们可以在cycle_analysis函数上应用一个循环来计算不同循环长度的预计回报和样本均方误差,并且我们在下图中显示了结果。正如我们所看到的,长度越长,每个周期的预计回报和样本均方误差会增加。 考虑到交易成本,每个周期内的预计回报应该大于10元。 在这种约束下,我们可以选择最小样本均方误差的周期,并且它是252天。 每个周期的预计回报为17.12元,样本均方误差为15.936。 两者都很不错!

  1. testing_box = range(10,301)
  2. return_box = []
  3. mse_box = []
  4. for c in testing_box:
  5. f = cycle_analysis(stock_data['close'],'2018-04-01',c)
  6. return_box.append(f[0])
  7. mse_box.append(f[1])
复制代码


  1. report = pd.DataFrame({'cycle':testing_box,'return':return_box,'mse':mse_box})
  2. possible_choice = report[report['return'] >10]
  3. possible_choice[possible_choice['mse']==min(possible_choice['mse'])]
复制代码



  1. c = possible_choice[possible_choice['mse']==min(possible_choice['mse'])]['cycle'].values[0]
  2. ycle_analysis(stock_data['close'],'2018-04-01',c,forecast_plot=True,print_ind=True)
复制代码

Projected return per cycle: 17.12 MSE: 15.9358 [17.120216439034987, 15.93576020351612]


为了进一步说明投资策略,我们可以看到2015/10/1和2018/10/1之间的买入和卖出日期。 Return_Dates函数可以将所有买入和卖出日期作为输出返回,输入:

  • forecast:fbprophet预测对象
  • stock_data:带有时间索引的Pandas数据
  • cycle:周期长度
  • cycle_name:预测对象中循环列的名称
  • time_name:预测对象中时间列的名称

  1. def Return_Dates(forecast,stock_data,cycle,cycle_name = 'self_define_cycle',time_name = 'ds'):
  2.    # find out the highest and lowest dates in the first cycle
  3.    # We cannot simply search for all highest and lowest point since there is slightly difference for high and low values in different cycles
  4.    high = forecast.iloc[:cycle,]
  5.    high = high[high[cycle_name]==max(high[cycle_name])][time_name]
  6.    high = datetime.strptime(str(high.values[0])[:10],"%Y-%m-%d")
  7.    low = forecast.iloc[:cycle,]
  8.    low = low[low[cycle_name]==min(low[cycle_name])][time_name]
  9.    low = datetime.strptime(str(low.values[0])[:10],"%Y-%m-%d")
  10.    end_dt = datetime.strptime(stock_data.index[-1],"%Y-%m-%d")
  11.    find_list = stock_data.index.map(lambda x:datetime.strptime(x,"%Y-%m-%d"))
  12.    # Finding selling and buying dates with loop
  13.    sell_dt = []
  14.    sell_dt.append(high)
  15.    # Looking for new cycle until it goes beyond the last date in stock_data
  16.    while high<end_dt:
  17.        high = high+timedelta(days=cycle)
  18.        dif = (find_list-high).days
  19.        high = find_list[abs(dif)==min(abs(dif))][0] # In order to avoid the non-trading dates
  20.        sell_dt.append(high)
  21.    buy_dt = []
  22.    buy_dt.append(low)
  23.    # Looking for new cycle until it goes beyond the last date in stock_data
  24.    while low<end_dt:
  25.        low = low+timedelta(days=cycle)
  26.        dif = (find_list-low).days
  27.        low = find_list[abs(dif)==min(abs(dif))][0] # In order to avoid the non-trading dates
  28.        buy_dt.append(low)
  29.    if buy_dt[0] > sell_dt[0]:
  30.        sell_dt = sell_dt[1:]
  31.    buy_dt = buy_dt[:-1]
  32.    sell_dt = sell_dt[:-1]
  33.    return [buy_dt,sell_dt]
复制代码

在2015/10/1和2018/10/1期间,我们买卖Costco四次。3年内的回报率为23.2%。 可能不是很吸引人,但至少它是比较乐观的回报。

更多股票的应用,当然,这种方法可以应用于尽可能多的股票。 我们列出了Costco,Apple,Microsoft,Home Depot和Nike的平均购买价格,平均销售价格,周期长度,样本均方误差,购买数量,销售数量和每个周期内的预计回报。

  1. Analysis_ticks = ['COST','AAPL','MSFT','HD','NKE']
  2. start_date = '2015-10-01'
  3. end_date = '2018-10-01'
  4. opt_cycle = []
  5. prot_return = []
  6. MSE = []
  7. buy_times = []
  8. sell_times = []
  9. avg_buy_price = []
  10. avg_sell_price = []
  11. # Loop over each stock
  12. for ticker in Analysis_ticks:
  13.    stock_data = data.DataReader(ticker, 'iex', start_date, end_date)
  14.    testing_box = range(50,301)
  15.    return_box = []
  16.    mse_box = []
  17.    for cc in testing_box:
  18.        f = cycle_analysis(stock_data['close'],'2018-04-01',cc)
  19.        return_box.append(f[0])
  20.        mse_box.append(f[1])
  21.    report = pd.DataFrame({'cycle':testing_box,'return':return_box,'mse':mse_box})
  22.    possible_choice = report[report['return'] >10]
  23.    # If we cannot find a cycle with return greater than 10, give 0
  24.    if possible_choice.shape[0]>0:
  25.        c = possible_choice[possible_choice['mse']==min(possible_choice['mse'])]['cycle'].values[0]
  26.        rp = possible_choice[possible_choice['mse']==min(possible_choice['mse'])]['return'].values[0]
  27.        mse = possible_choice[possible_choice['mse']==min(possible_choice['mse'])]['mse'].values[0]
  28.        df = stock_data[:'2018-04-01'].iloc[:-1,]['close'].reset_index()
  29.        df.columns = ['ds','y']
  30.        predict_period = len(pd.date_range('2018-04-01','2018-10-01'))
  31.        m = Prophet(weekly_seasonality=False,yearly_seasonality=False,daily_seasonality=False)
  32.        m.add_seasonality('self_define_cycle',period=c,fourier_order=8,mode='additive')
  33.        m.fit(df)
  34.        future = m.make_future_dataframe(periods=predict_period)
  35.        forecast = m.predict(future)
  36.        dt_list = Return_Dates(forecast,stock_data,c)
  37.        buy_price = stock_data.loc[map(lambda x: x.strftime("%Y-%m-%d"),dt_list[0])]['close']
  38.        sell_price = stock_data.loc[map(lambda x: x.strftime("%Y-%m-%d"),dt_list[1])]['close']
  39.        bt = buy_price.shape[0]
  40.        st = sell_price.shape[0]
  41.        bp = np.mean(buy_price)
  42.        sp = np.mean(sell_price)
  43.    else:
  44.        c = 0
  45.        rp = 0
  46.        mse = 0
  47.        bt = 0
  48.        st = 0
  49.        bp = 0
  50.        sp = 0
  51.    opt_cycle.append(c)
  52.    prot_return.append(rp)
  53.    MSE.append(mse)
  54.    buy_times.append(bt)
  55.    sell_times.append(st)
  56.    avg_buy_price.append(bp)
  57.    avg_sell_price.append(sp)
  58.    print "{} Finished".format(ticker)
复制代码


对于微软和耐克,我们找不到符合我们要求每个周期超过10元回报的周期。 对于Costco,Apple和Home Depot,我们可以找到大约250天的周期,并做出良好的预测和良好的回报。

  1. stock_report = pd.DataFrame({'Stock':Analysis_ticks,'Cycle':opt_cycle,'Projected_Return_per_Cycle':prot_return,
  2.                         'MSE':MSE,'Num_of_Buy':buy_times,'Num_of_Sell':sell_times,
  3.                         'Average_Buy_Price':avg_buy_price,'Average_Sell_Price':avg_sell_price})
  4. stock_report
复制代码

总结

借助Python和fbprophet包,我们可以更好地了解股市。 根据我们发现的周期,我们可以在3年内获得大约23%的回报。 也许这种投资策略无法满足所有人的需求,但你始终可以根据自己的知识和经验设定自己的方法。 强大的fbprophet软件包可以让你对股票市场的分析更加深入和轻松。


延伸阅读:

经典的深度学习教程及Python代码实现

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:股市 Python分析 周期 Python 分析周期

沙发
endimirion 发表于 2018-10-16 13:30:35
A股也能适用吗。。

藤椅
kukenghuqian 发表于 2018-10-16 13:47:39

板凳
heiyaodai 发表于 2018-10-17 19:51:43
谢谢分享。

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群
GMT+8, 2026-1-22 14:26