import sys
sys.path.insert(0, "../../")
from pyecharts import online
online()
# 演示必要的准备代码,使用该库时不需重复此单元格命令
import xalpha as xa
import pandas as pd
生成简单的策略投资交易单,并储存在 self.status 中
jshs = xa.fundinfo("000311")
# 选择投资标的
bah = xa.policy.buyandhold(jshs, start="2017-01-01", totmoney=100000)
# 简单的一次性买入类,从 start 日买入后就一直持有,始终选择分红再投入
bah.status
# 第二三列表示此两日恰为分红日,选择了分红再投入
000311 | date | |
---|---|---|
0 | 100000.00 | 2017-01-03 |
1 | 0.05 | 2017-08-04 |
2 | 0.05 | 2017-08-15 |
jshs.fenhongdate
# 验证该两日确实分红
[Timestamp('2017-08-04 00:00:00'), Timestamp('2017-08-15 00:00:00')]
bah.sellout("2018-06-01") # 选定日期全部卖出
bah.status
000311 | date | |
---|---|---|
0 | 100000.000 | 2017-01-03 |
1 | 0.050 | 2017-08-04 |
2 | 0.050 | 2017-08-15 |
3 | -0.005 | 2018-06-01 |
jshstrade = xa.trade(jshs, bah.status) # 尝试交易一下
jshstrade.xirrrate()
0.15629726951248488
# 依旧先制定标的
zzcm = xa.fundinfo("164818")
zzcm
工银中证传媒指数分级
auto = xa.policy.scheduled(
zzcm, 1000, pd.date_range("2015-07-01", "2018-07-01", freq="W-THU")
)
# 按照每周四定额定投1000,生成交易单
# 按上面的策略单子交易下
cm_t3 = xa.trade(zzcm, auto.status)
cm_t3.v_tradevolume() # 交易情况可视化,那些明显的缝隙对应了小长假等,当次定投下单会被自动延后到下一个交易日
cm_t3.dailyreport("2018-08-03") ## 截止到2018.08.03, 定投已经浮亏了 40% 多
基金名称 | 基金代码 | 当日净值 | 单位成本 | 持有份额 | 基金现值 | 基金总申购 | 历史最大占用 | 基金持有成本 | 基金分红与赎回 | 换手率 | 基金收益总额 | 投资收益率 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 工银中证传媒指数分级 | 164818 | 0.935 | 1.6141 | 96030.82 | 89788.82 | 155000.0 | 155000.0 | 155000.0 | 0.0 | 0.161791 | -65211.18 | -42.0717 |
还可以根据指数位置设置定期不定额的定投策略生成,这里就不仔细展开,只给一个例子:
auto2 = xa.policy.scheduled_tune(
zzcm,
1000,
pd.date_range("2015-07-01", "2018-07-01", freq="M"),
[(0.9, 2), (1.2, 1)],
) # 净值0.9以下加倍定投,1.2以上不再定投,中间正常定投
cm_t4 = xa.trade(zzcm, auto2.status)
cm_t4.v_tradevolume()
gfc = xa.fundinfo("002903")
gfc
# 场外网格最好选择基金的C份额
广发中证500ETF联接C
gr = xa.policy.grid(
gfc, [3, 3, 3, 3, 3, 3], [6, 6, 6, 6, 6, 6], "2017-01-01", "2018-08-03"
)
# 制定一个 17年开始,18年8月结束的,以开始日期价格为基准,每下跌3%买入一仓,每仓买入上涨6%后卖出的网格策略,一共设置6档
## 注意网格对应的总金额可通过 totmoney= 参数设置,这里默认值是100000
## 卖出实际并不严格对应每次买入的份额,而是买入均分金额分仓,卖出均分持有份额分仓
gr.sellpts, gr.buypts # 网格计划对应的卖点和买点净值
([1.09791196, 1.0649746012000001, 1.0330253631639998, 1.0020346022690798, 0.97197356420100745, 0.9428143572749772], [1.035766, 1.0046930199999999, 0.97455222939999986, 0.94531566251799981, 0.91695619264245976, 0.88944750686318597])
gfc.price.iloc[-4:-1] # 事实上中证500已大幅跌破网格底线
comment | date | netvalue | totvalue | |
---|---|---|---|---|
524 | 0 | 2018-08-07 | 0.8629 | 0.8629 |
525 | 0 | 2018-08-08 | 0.8503 | 0.8503 |
526 | 0 | 2018-08-09 | 0.8713 | 0.8713 |
gfc_t = xa.trade(gfc, gr.status) # 请开始你的交易
gfc_t.v_tradevolume(bar_category_gap="90%") # 交易情况可视化
gfc_t.xirrrate("2018-04-01") # 截止指定日期的年化收益率超过50%
0.5110637968744924
gfc_t.xirrrate() # 随着18年六七月份市场大跌,网格被跌穿,收益年化转负
-0.031232122333919685
gfc_t.v_totvalue() # 网格投资持有基金的总值情况
# 考虑到网格的闲置资金可以在货基中吃收益,于是使用投资组合分析
gfc_cb = xa.mulfix(
gfc_t, cashobj=xa.cashinfo(start="2016-10-01")
) # 恰好 mulfix 类的默认 totmoney 也是 100000,我们无需在额外设置
gfc_cb.combsummary()
基金名称 | 基金代码 | 当日净值 | 单位成本 | 持有份额 | 基金现值 | 基金总申购 | 历史最大占用 | 基金持有成本 | 基金分红与赎回 | 换手率 | 基金收益总额 | 投资收益率 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 广发中证500ETF联接C | 002903 | 0.875800 | 0.8860 | 106310.30 | 93106.56 | 183333.37 | 94193.05 | 94193.05 | 89140.32 | 0.922938 | -1086.49 | -1.1535 |
1 | 货币基金 | mf | 1.070148 | 0.5975 | 9719.33 | 10401.12 | 172473.65 | 103397.46 | 5806.95 | 166666.70 | 1.046493 | 4594.17 | 4.4432 |
2 | 总计 | total | NaN | NaN | NaN | 103507.68 | 355807.02 | 100000.00 | 100000.00 | 255807.02 | 0.319056 | 3507.68 | 3.5077 |
gfc_cb.xirrrate() # 系统总计收益年化勉强为正
0.022243013394994196
利用模块内置的海量技术指标,可以制定各种基于不同技术指标的交叉进行交易的策略,同样的也可以指定基于净值和单个技术指标交叉的策略
hs300 = xa.indexinfo("0000300") # 获取指数作为假想的无摩擦成本的投资标的
hs300.ma(window=14) # 生成指数14天的均线
hs300.price.iloc[-1] # 此时 info 类的 price 表将自动添加一列 MA14
date 2018-08-16 00:00:00 netvalue 2.48904 totvalue 3276.73 comment 0 MA14 2.5641 Name: 4032, dtype: object
hs300.v_techindex(col=["MA14"], is_symbol_show=False) # 均线和指数的纠缠
st = xa.policy.indicator_cross(hs300, start="2013-01-01", col=("netvalue", "MA14"))
# col 参量为一个两字符串的 tuple,每个代表标的价格表的一列名,当前者上穿后者时买入,反之卖出
# 具体到这里,就是最经典的一个趋势短线策略,价格涨过某条均线就买入,反之卖出
hs300_t = xa.trade(hs300, st.status) # 模拟真实交易
hs300_t.dailyreport() # 盈利一般
基金名称 | 基金代码 | 当日净值 | 单位成本 | 持有份额 | 基金现值 | 基金总申购 | 历史最大占用 | 基金持有成本 | 基金分红与赎回 | 换手率 | 基金收益总额 | 投资收益率 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 沪深300 | 0000300 | 2.489045 | 0 | 0.0 | 0.0 | 9800000.0 | 112302.79 | -41009.61 | 9841009.61 | 16.047277 | 41009.61 | 36.517 |
hs300_t.v_tradevolume() # 交易详情,相当高频,换手率 16 代表每笔的持有时间约为 1/16 年,即不到一个月
hs300_t.v_tradecost(is_symbol_show=False) # 持仓成本降低缓慢
sti = xa.policy.indicator_cross(hs300, start="2013-01-01", col=("MA14", "netvalue"))
# 我们看下交易策略彻底反转会发生什么
hs300_ti = xa.trade(hs300, sti.status)
hs300_ti.dailyreport() # 跌穿均线买入涨出均线卖出,果然赔钱,噗
基金名称 | 基金代码 | 当日净值 | 单位成本 | 持有份额 | 基金现值 | 基金总申购 | 历史最大占用 | 基金持有成本 | 基金分红与赎回 | 换手率 | 基金收益总额 | 投资收益率 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 沪深300 | 0000300 | 2.489045 | 2.597 | 38187.17 | 95049.57 | 9900000.0 | 113045.02 | 99170.71 | 9800829.29 | 15.870778 | -4121.14 | -3.6456 |
除了指标间的交叉,我们还可以给定几个不同的点位来买卖,其中也可以不给卖的点位,这相当于可以模拟熊市的网格底仓
hs300.roc(window=20) # 先生成一个追涨杀跌的动量类变动率指标
st = xa.policy.indicator_points(
hs300,
start="2016-01-01",
col="ROC20",
buy=[(-0.08, 1), (-0.11, 2)],
sell=[(0.06, 1), (0.1, 1)],
buylow=True,
)
# 这个策略的含义时,跌破点位买,涨破点位跌, 这是 buylow 这个布尔量的意义,默认就是 true
# 点位看的是 ROC20 一栏,这是 col 参数决定的,交易从 16年开始,默认昨天结束
# 买点分别是 ROC 的值为 -8% 和 -11%, 分别买1/3,和2/3
# 卖点分别是 ROC 为 6% 和 8%, 各卖一半
hs300_t = xa.trade(hs300, st.status)
hs300_t.dailyreport() # 追跌杀涨好像效果一般
基金名称 | 基金代码 | 当日净值 | 单位成本 | 持有份额 | 基金现值 | 基金总申购 | 历史最大占用 | 基金持有成本 | 基金分红与赎回 | 换手率 | 基金收益总额 | 投资收益率 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 沪深300 | 0000300 | 2.489045 | 2.7577 | 37516.8 | 93380.99 | 200000.0 | 103461.1 | 103461.1 | 96538.9 | 0.549453 | -10080.11 | -9.7429 |
hs300_t.v_totvalue() # 持有总金额的变化