备注:
09pandas基础(下)
10择时策略框架(一)(上) 已经完成
......
25 已经完成
Feb-23-2020 全部学完。
一、资源
1.计算指标(第20课)
年化收益 = pow(总收益,365/天数)
2.pandas (花1.5小时即可学完)
查看pandas所有函数:https://pandas.pydata.org/pandas-docs/stable/reference/index.html
二、双均线策略回测
2 | df = df[[ '交易日期' , '股票代码' , '开盘价' , '最高价' , '最低价' , '收盘价' , '涨跌幅' , 'pos' ]] |
3 | df.reset_index(inplace=True, drop=True) |
6 | initial_money = 1000000 # 初始资金,默认为1000000元 |
7 | slippage = 0.01 # 滑点,默认为0.01元 |
8 | c_rate = 5.0 / 10000 # 手续费,commission fees,默认为万分之5 |
9 | t_rate = 1.0 / 1000 # 印花税,tax,默认为千分之1 |
12 | df.at[0, 'hold_num' ] = 0 # 持有股票数量,此处也可用loc,但是定位单个元素at效率更高。 |
13 | df.at[0, 'stock_value' ] = 0 # 持仓股票市值 |
14 | df.at[0, 'actual_pos' ] = 0 # 每日的实际仓位 |
15 | df.at[0, 'cash' ] = initial_money # 持有现金现金 |
16 | df.at[0, 'equity' ] = initial_money # 总资产 = 持仓股票市值 + 现金 |
17 | # print df[[ '交易日期' , '开盘价' , 'pos' , 'hold_num' , 'stock_value' , 'actual_pos' , 'cash' , 'equity' ]] |
21 | for i in range(1, df.shape[0]): |
24 | hold_num = df.at[i - 1, 'hold_num' ] |
26 | # 判断当天是否除权,若发生除权,需要调整hold_num |
27 | # 若当天通过收盘价计算出的涨跌幅,和当天实际涨跌幅不同,说明当天发生了除权 |
28 | if abs ((df.at[i, '收盘价' ] / df.at[i-1, '收盘价' ] - 1) - df.at[i, '涨跌幅' ]) > 0.001: |
29 | stock_value = df.at[i - 1, 'stock_value' ] |
31 | last_price = df.at[i, '收盘价' ] / (df.at[i, '涨跌幅' ] + 1) |
32 | hold_num = stock_value / last_price |
33 | hold_num = int(hold_num) |
35 | # print stock_value, last_price, hold_num |
36 | # print df.iloc[1034:][[ '交易日期' , '收盘价' , '涨跌幅' , 'pos' , 'hold_num' , 'cash' , 'stock_value' ]] |
38 | # 判断是否需要调整仓位:拿今天的仓位pos,和昨天的仓位pos进行比较,看是否相同 |
40 | if df.at[i, 'pos' ] != df.at[i - 1, 'pos' ]: |
43 | # 昨天的总资产 * 今天的仓位 / 今天的收盘价,得到需要持有的股票数 |
44 | theory_num = df.at[i - 1, 'equity' ] * df.at[i, 'pos' ] / df.at[i, '开盘价' ] |
46 | theory_num = int(theory_num) # 向下取整数,向上取整会出现钱不够的情况 |
48 | # 将theory_num和昨天持有股票相比较,判断加仓还是减仓 |
50 | if theory_num >= hold_num: |
52 | buy_num = theory_num - hold_num |
53 | # 买入股票只能整百,对buy_num进行向下取整百 |
54 | buy_num = int(buy_num / 100) * 100 |
57 | buy_cash = buy_num * (df.at[i, '开盘价' ] + slippage) |
58 | # 计算买入股票花去的手续费,并保留2位小数 |
59 | commission = round (buy_cash * c_rate, 2) |
61 | if commission < 5 and commission != 0: |
63 | df.at[i, '手续费' ] = commission |
66 | df.at[i, 'hold_num' ] = hold_num + buy_num # 持有股票,昨天持有的股票,加上今天买入的股票 |
67 | df.at[i, 'cash' ] = df.at[i - 1, 'cash' ] - buy_cash - commission # 剩余现金 |
68 | # print df[[ '交易日期' , '开盘价' , 'pos' , 'hold_num' , 'cash' , '手续费' ]] |
73 | # 计算卖出股票数量,卖出股票可以不是整数,不需要取整百。 |
74 | sell_num = hold_num - theory_num |
77 | sell_cash = sell_num * (df.at[i, '开盘价' ] - slippage) |
78 | # 计算手续费,不足5元按5元收,并保留2位小数 |
79 | commission = round (max(sell_cash * c_rate, 5), 2) |
80 | df.at[i, '手续费' ] = commission |
81 | # 计算印花税,保留2位小数。历史上有段时间,买入也会收取印花税 |
82 | tax = round (sell_cash * t_rate, 2) |
86 | df.at[i, 'hold_num' ] = hold_num - sell_num # 持有股票 |
87 | df.at[i, 'cash' ] = df.at[i - 1, 'cash' ] + sell_cash - commission - tax # 剩余现金 |
88 | # print df.iloc[50:100][[ '交易日期' , '开盘价' , 'pos' , 'hold_num' , 'cash' , '手续费' , '印花税' ]] |
93 | df.at[i, 'hold_num' ] = hold_num # 持有股票 |
94 | df.at[i, 'cash' ] = df.at[i - 1, 'cash' ] # 剩余现金。此处的cash可以乘以余额宝的收益率。 |
95 | # print df[[ '交易日期' , 'pos' , 'hold_num' , 'cash' ]] |
97 | # 以上的计算得到每天的hold_num和cash |
99 | df.at[i, 'stock_value' ] = df.at[i, 'hold_num' ] * df.at[i, '收盘价' ] # 股票市值 |
100 | df.at[i, 'equity' ] = df.at[i, 'cash' ] + df.at[i, 'stock_value' ] # 总资产 |
101 | df.at[i, 'actual_pos' ] = df.at[i, 'stock_value' ] / df.at[i, 'equity' ] # 实际仓位 |
103 | # print df[[ '交易日期' , 'pos' , 'cash' , 'stock_value' , 'equity' , 'actual_pos' ]] |
106 | df = df[[ '交易日期' , '收盘价' , 'pos' , 'hold_num' , 'cash' , 'stock_value' , 'equity' , 'actual_pos' , '手续费' , '印花税' ]] |
109 | # print df[[ '手续费' , '印花税' ]].sum() |