当前位置:   article > 正文

深入浅出Python量化交易实战chapter2_基于python的量化投资策略的代码

基于python的量化投资策略的代码

目录

(1)低买高卖简单回测

(2)单一移动平均策略

(3)双移动平均策略

(4)海龟策略 

(1)低买高卖简单回测

“低买高卖”策略。每次都在相对低点买入,并且在相对高点卖出(跌了买,涨了卖)。下面进行简单回测:

1.导入库

  1. # 导入库
  2. from pandas_datareader import data as dt
  3. import yfinance as yf
  4. yf.pdr_override()
  5. import pandas as pd
  6. import numpy as np
  7. import matplotlib.pyplot as plt
  8. import seaborn as sns

 2.获取数据

  1. start_date = '2020-01-01'
  2. end_date = '2020-03-20'
  3. # 提取数据:中国平安股票数据
  4. zgpa = dt.get_data_yahoo('601318.ss',start_date,end_date)
  5. zgpa.head()

输出: 

 3.设定交易信号

  1. # 交易信号
  2. zgpa_signanl = pd.DataFrame(index = zgpa.index) # 日期index
  3. zgpa_signanl['price'] = zgpa['Adj Close'] # 调整价格作为股票价格
  4. zgpa_signanl['diff'] = zgpa_signanl['price'].diff() #股价变化
  5. zgpa_signanl = zgpa_signanl.fillna(0.0) #第一个空值填充为0
  6. zgpa_signanl['signal'] = np.where(zgpa_signanl['diff']>=0,0,1) #股价上涨或不变记为0,下跌记为1
  7. zgpa_signanl['order'] = zgpa_signanl['signal'].diff()*100 #买入/卖出1手(100股),股价上涨:卖出,股价下跌:买入
  8. zgpa_signanl.head()

输出:

4.回测

  1. # 回测
  2. initial_cash = 20000.00 # 初始资金2万元
  3. # 股票市值
  4. zgpa_signanl['stock'] = zgpa_signanl['order']*zgpa_signanl['price']
  5. # 剩余现金=初始现金-现金流变化的累加
  6. zgpa_signanl['cash'] = initial_cash -(zgpa_signanl['order'].diff()*zgpa_signanl['price']).cumsum()
  7. #总资产=股票+现金
  8. zgpa_signanl['total'] = zgpa_signanl['stock'] +zgpa_signanl['cash']
  9. # 绘图
  10. plt.figure(figsize=(8,5))
  11. plt.plot(zgpa_signanl['total'],label = 'total') #总资产
  12. plt.plot(zgpa_signanl['order'].cumsum()*zgpa_signanl['price'],'--',label = 'stock value') #持仓股票市值
  13. plt.grid(True)
  14. plt.legend(loc='center right')
  15. plt.show()

输出:

(2)单一移动平均策略

当股价上升且向上穿过N日的均线时,说明股价向上突破,此时下单买入;当股价下降且向下穿过N日均线,说明股价出现下跌趋势,此时下单卖出。或者当M日均价上升穿过N日的均线(M < N)时,说明股票处上升的趋势,下单买入;反之,当M日均价下降且穿过N日均线时,说明股票处于下降趋势,下单卖出。
 

1.这里指标使用10日均线:

  1. period = 10 #10日均线
  2. avg_10=[] # 储存10天的价格
  3. avg_value=[] # 储存10天价格的均值
  4. for price in zgpa['Adj Close']:
  5. avg_10.append(price)
  6. if len(avg_10) >period:
  7. del avg_10[0]
  8. avg_value.append(np.mean(avg_10))
  9. # 将10日均价写到股票价格数据表中
  10. zgpa = zgpa.assign(avg_10 = pd.Series(avg_value, index= zgpa.index))
  11. zgpa.head()

输出:
 

2.画个10日均线的图

  1. plt.figure(figsize=(10,6))
  2. plt.plot(zgpa['Adj Close'],lw = 2,c ='k',label = 'stock price') # stock price,股价
  3. plt.plot(zgpa['avg_10'],'--',lw =2 ,c ='b',label = 'avg_10') # avg_10,10日均价
  4. plt.grid(True)
  5. plt.legend()
  6. plt.show()

输出:

(3)双移动平均策略

使用两条均线判断股价未来的走势。一条是长期均线(如20日均线),另一条是短期均线(如5日均线)。这种策略基于这样一种假设:股票价格的动量会朝着短期均线的方向移动。当短期均线穿过过长期均线,超过长期移动平均线时,动量将向上,此时股价可能会上涨。然而,如果短期均线的移动方向相反,则股价可能下跌。

1.策略代码:

  1. strategy = pd.DataFrame(index=zgpa.index)
  2. strategy['signal'] = 0 # 存储交易信号
  3. strategy['avg_5'] = zgpa['Adj Close'].rolling(5).mean() # 5日均价
  4. strategy['avg_10'] = zgpa['Adj Close'].rolling(10).mean() # 10日均价
  5. strategy['signal'] = np.where(strategy['avg_5']>strategy['avg_10'],1,0) # 5日均价avg_5>10日均价avg_10时动量向上,股价可能上涨,标记为1(avg_5<avg_10时,股价可能下跌,标记为0)
  6. strategy['order'] = strategy['signal'].diff() # 信号从0变1,买入,从1变0,卖出
  7. strategy

输出:

2.画个图看看该策略在哪里买/卖

  1. plt.figure(figsize=(10,5))
  2. plt.plot(zgpa['Adj Close'],lw = 2,label = 'price') # stock price
  3. plt.plot(strategy['avg_5'],lw = 2,ls ='--',label = 'avg5') # stock price
  4. plt.plot(strategy['avg_10'],lw = 2,ls ='-.',label = 'avg10') # stock price
  5. plt.scatter(strategy.loc[strategy['order']==1].index,
  6. zgpa['Adj Close'][strategy['order']==1],
  7. marker='^',s = 80, c = 'r', label = 'Buy') # 标出买入信号
  8. plt.scatter(strategy.loc[strategy['order']==-1].index,
  9. zgpa['Adj Close'][strategy['order']==-1],
  10. marker='v',s = 80, c = 'g', label = 'Sell') # 标出卖出信号
  11. plt.legend()
  12. plt.grid(True)
  13. plt.show()

输出:

3.对该策略回测:

  1. ## 回测
  2. initial_cash = 20000.00 # 初始资金2万元
  3. positions = pd.DataFrame(index = strategy.index).fillna(0)
  4. positions['stock'] = strategy['signal']*100 # 买卖1手100股
  5. portfolio = pd.DataFrame()
  6. portfolio['stock value'] = positions.multiply(zgpa['Adj Close'], axis = 0) # 持仓股票*股价=股票市值
  7. # multiply 对应位置上两个对象元素的乘积
  8. order = positions.diff() # 下单数量
  9. # 剩余资金 = 初始资金 - 下单金额的总和
  10. portfolio['cash'] = initial_cash - order.multiply(zgpa['Adj Close'], axis = 0).cumsum()
  11. # 总资产 = 剩余资金 + 持仓股票市值
  12. portfolio['total'] = portfolio['cash'] + portfolio['stock value']
  13. portfolio

输出(看看portfolio):

画个图看下:

  1. plt.figure(figsize=(10,5))
  2. plt.plot(portfolio['total'], lw=2, label = 'total') # 总资产
  3. plt.plot(portfolio['stock value'], lw=2, label = 'stock value') # 持仓股票市值
  4. plt.legend()
  5. plt.grid(True)
  6. plt.show()

该时间区间市场下跌,该策略总体上还是亏钱的。

(4)海龟策略 

在股价超过过去N个交易日的股价最高点时买入,在股价低于过去N个交易日的股价最低点时卖出。上述的若干个最高点和最低点会组成一个通道,称“唐奇安通道”。

使用过去N天的股价最高点和过去N天的股价最低点生成唐奇安通道。一般来说,N会设置为20。不过因为我们下载的股票数据时间范围跨度比较小,所以选择了使用过去5日的股价最高点和最低点来进行演示。

1.策略信号:

  1. turtle = pd.DataFrame(index= zgpa.index)
  2. turtle['high'] = zgpa['Adj Close'].shift(1).rolling(5).max()
  3. turtle['low'] = zgpa['Adj Close'].shift(1).rolling(5).min()
  4. turtle['buy'] = zgpa['Adj Close'] > turtle['high'] #股价突破上沿,买入
  5. turtle['sell'] = zgpa['Adj Close'] < turtle['low'] #股价突破下沿,卖出
  6. turtle

输出:

2.根据交易信号和仓位进行下单
交易信号为“买入”且空仓时,才下买入订单;交易信号为“卖出”且有持仓股票时,才会下卖出订单

  1. turtle['orders'] = 0 # 初始订单状态为0
  2. position = 0 # 初始仓位0
  3. for k in range(len(turtle)):
  4. if turtle.buy[k] and position == 0: # 买入信号为true且空仓时买入1手:
  5. turtle.orders[k] = 1
  6. position = 1
  7. elif turtle.sell[k] and position > 0:
  8. turtle.orders[k] = -1
  9. position = 0
  10. turtle

输出:

3.画图看下买/卖时机:

  1. plt.figure(figsize=(10, 5))# 设置画布的尺寸0
  2. plt.plot(zgpa['Adj Close'], lw=2, label='stock') #股价折线图
  3. # 唐奇安通道的上沿
  4. plt.plot(turtle['high'], lw=2, ls='--',c='r', label='high')
  5. # 唐奇安通道的下沿
  6. plt.plot(turtle['low'], lw=2, ls='--',c='g', label='low')
  7. #将买入信号用正三角标识
  8. plt.scatter(
  9. turtle.loc[turtle.orders == 1].index,
  10. zgpa['Adj Close'][turtle.orders == 1],
  11. marker='^', s=80, c='r', label='buy')
  12. #将卖出信号用倒三角标识
  13. plt.scatter(turtle.loc[turtle.orders == -1].index,
  14. zgpa['Adj Close'][turtle.orders == -1],
  15. marker='v', s=80, c='g', label='shell')
  16. plt.legend()
  17. plt.grid()
  18. plt.show()

输出:

4.回测:

  1. # 回测
  2. # 初始资金
  3. initial_cash = 20000
  4. # 创建新的数据表,序号和turtle数据表一致
  5. positions = pd.DataFrame(index=turtle.index).fillna(0.0)
  6. # 每次交易为1手(100股),仓位既买单和卖单的累积加和
  7. positions['stock'] = 100 * turtle['orders'].cumsum()
  8. # 创建投资组合数据表
  9. portfolio = positions.multiply(zgpa['Adj Close'], axis=0)
  10. # 持仓市值为持仓股票数乘以股价
  11. portfolio['holding_values'] = positions.multiply(zgpa['Adj Close'], axis=0)
  12. # 计算出仓位的变化
  13. pos_diff = positions.diff()
  14. # 剩余的现金是初始资金减去仓位变化产生的现金流累计加和
  15. portfolio['cash'] = initial_cash - (pos_diff.multiply(zgpa['Adj Close'], axis=0)).cumsum()
  16. # 总资产既持仓股票市值加剩余现金
  17. portfolio['total'] = portfolio['cash'] + portfolio['holding_values']
  18. portfolio

输出:

画图看下:

  1. #画图
  2. plt.figure(figsize=(10, 5))
  3. plt.plot(portfolio['total'], label='total')
  4. plt.plot(portfolio['holding_values'], '--', label='holding_values') #持仓股票是市值
  5. plt.legend()
  6. plt.grid()
  7. plt.show()

输出:

可以看到该策略还是亏钱(最后剩余19549元)的。但是比双移动平均策略(剩余19413元)赔的少一些,表明该策略更优。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/836178
推荐阅读
相关标签
  

闽ICP备14008679号