1.学习《深入浅出python量化交易交易实战》第二章(笔记1)
记录学习过程中的代码、疑问和心得
2 回测
名词
本章节提到的金融名字和解释
- PnL: 利润和损失(Profit and Loss)
- net PnL: 净利润和损失
- 年化收益
- 交易手数
- 风险敞口(exposure):是指未加保护的风险,在股市中,其实是指投资股票的资金。
例如:牛顿有1万元,他拿其中的5000元买了股票,其余5000元买了保本的理财产品,那么买股票的5000元就面临这下跌的风险。也就是说他的风险敞口就是5000元。
- 夏普指数(sharpe ratio): 将一组投资组合的回报率与无风险投资(银行存款、国债)回报率进行对比。
夏普指数越高,说明投资组合回报率越高;相反,如果投资组合回报不及无风险投资回报,就是说明投资是不应该进行的。
假设:牛顿买了保本理财产品的收益是4%,而投资股票的预期收益是100%,同时,投资股票的超额收益指标差是20%,则牛顿进行股票投资的夏普指数是:
(100%),同时,投资股票的超额收益标准差是20%,则牛顿进行股票投资的夏普指数是:
(100% - 4%)/ 20% = 4.8
- 超额收益指标差: 方差开根号
- 方差(n为总体数据)=((x1-m)^2 + … (xn-m)^2) / n;
- 方差(n为总体数据样本数据)=((x1-m)^2 + … (xn-m)^2) / n - 1;
- 标准差和方差
1. 回测第一章重的简单交易策略
书中的代码没有对方法进行非封装,这里我自己将获取股票数据并组装数据封装成一个方法gen_stock_data_table
:
'''
- 回测
- python实现简单回测
'''
import pandas as pd
import numpy as np
import akshare as ak
def gen_stock_data_table(symbol, start_date, end_date):
print(symbol, start_date, end_date)
stock = ak.stock_zh_a_hist(symbol=symbol,
period="daily",
start_date=start_date,
end_date=end_date, adjust="hfq")
print('------原始数据处理---------', stock)
stock = pd.DataFrame(stock, columns=['日期', '开盘', '最高', '最低', '收盘', '成交量'])
stock.rename(columns={
'日期': 'date',
'开盘': 'open',
'最高': 'high',
'最低': 'low',
'收盘': 'close',
'成交量': 'volume'
},
inplace=True)
stock.index = pd.DatetimeIndex(stock['date'])
return {'stock': stock}
回测代码:
import numpy as np
import pandas as pd
from chapter_2_get import gen_stock_data_table
import matplotlib.pyplot as plt
import seaborn as sns # seaborn是python中的一个可视化库,是对matplotlib进行二次封装
'''
回测交易策略
'''
# 初始资金
initial_cash = 20000.00
stock_data = gen_stock_data_table('002419', '20220101', '20221231')
stock_data = stock_data['stock']
# 1. 创建交易账号
# 2. 为了不影响原始数据,创建一个新的数据表
# 创建一个新表,只保留原始数据重的日期index
stock_002419_signal = pd.DataFrame(index=stock_data.index)
# 使用close作为股票价格
stock_002419_signal['price'] = stock_data['close']
# 增加diff字段,存储股价变化
print('------增加diff字段,存储股价变化,出现NaN---------')
stock_002419_signal['diff'] = stock_002419_signal['price'].diff()
print(stock_002419_signal.head(10))
# 增加diff字段后,第一行会出现空值,使用0来进行填补
print('------NaN用0.0填补------')
stock_002419_signal = stock_002419_signal.fillna(0.0)
print(stock_002419_signal.head(10))
print('------使用signal标记估计上涨或不变:0(卖出),下跌:1(买入)---------')
stock_002419_signal['signal'] = np.where(stock_002419_signal['diff'] >= 0, 0, 1)
print(stock_002419_signal.head(10))
print('------根据交易信号进行下单---------')
print('------卖/买出100股---------')
'''
相对于前一天不变不操作
相对于前一天下跌:买入100股
相对于前一天上涨:卖出100股
'''
# order买入或卖出,hold持仓数
stock_002419_signal['order'] = stock_002419_signal['signal'].diff() * 100
stock_002419_signal['hold'] = stock_002419_signal['order'].cumsum()
# stock_002419_signal = stock_002419_signal.fillna('--')
# 增加trade_stock字段代表 交易股票的市值
stock_002419_signal['trade_stock'] = stock_002419_signal['order'] * stock_002419_signal['price']
# 现金流变化, pd.cumsum()累加函数
# 单次交易金额
stock_002419_signal['use_cash'] = -stock_002419_signal['trade_stock']
# 累加值
stock_002419_signal['use_cash_cum_sum'] = stock_002419_signal['use_cash'].cumsum()
# 初始金额 + 现金流累加(已转换了正负) = 剩余金额;
stock_002419_signal['cash'] = initial_cash + stock_002419_signal['use_cash_cum_sum']
# 持仓市值+现金=总资产
stock_002419_signal['total'] = stock_002419_signal['hold'] * stock_002419_signal['price'] + stock_002419_signal['cash']
print('-------结果--------')
print(stock_002419_signal.head(10))
# 导出表格
stock_002419_signal.head(30).to_excel('dahua_002419.xls')
'''
用图形表示
总资产
持仓市值
'''
plt.figure(figsize=(10, 6))
plt.plot(stock_002419_signal['total'], '-', label='total assets') # 总资产
plt.plot(stock_002419_signal['hold'] * stock_002419_signal['price'], '--', label='hold stock') # 持仓市值
plt.grid()
plt.legend(loc='center right')
plt.show()