大家好,又见面了,我是你们的朋友全栈君。
前言
2021年转瞬即逝,回顾一下在蚂蚁上定投的基金,在金融危机风雨欲来的2022年,分享一个懒人版的理财策略,愿大家新年里能财源广进,元旦快乐。
基金定投
我的策略非常简单,每月无脑小额定投,等”全民炒股”这种话题上新闻,择时清仓。一般2-3年有一个操作点,每次操作窗口期几个月,错过就从头再来。卖出点不影响买入操作,循环往复。
为什么选择基金
-
每月一次或几次交易,不影响本职工作,繁复的工作交给机器来做。
-
基金可以规避单一股票的对应行业或公司的黑天鹅事件。比如乐视的”下周回国”,或是“双减”对整个教育行业的冲击。
-
相对股票来说,基金更“永续”,更少的停牌,ST或是增发干扰。
-
在瞬息万变的股票市场,政策的影响度,舆情的提取手段尚不成熟,基金对于普通人来说可以大幅度简化投资模型。
为什么选择指数基金
-
公募基金的基金经理有”业绩原罪”,即不惜一切代价追求高利润率,因为这样才能让排名靠前,才能让投资者”看到”。这种激励机制下,交易员更偏向冒险的投资风格,赌赢手续费赚的盆满钵满,赌输不过是换个基金代号从头再来。
-
基金经理策略会与我们的自主策略混淆,无法归因,无法回测和改进策略,指数基金则减少了“个人”风险的集中度。
为什么选择定投策略
-
定投不择时,相对模型简化了一个变量。
-
小额定期交易可以更好的小步试错,累积时序数据。
-
A股的“「熊长牛短」“特征,意味着间隔平均的投资点大概率会落于熊市的低位,降低成本。
关于高频交易
-
对于普通投资者来说,高频交易策略的手续费偏高,非金融专业的知识储备不足。
-
A股的T+1也相对限制了个股上交易操作(若资金量大可以做T改善这个问题,但也面临资金冲击现象)。
-
基金作为一揽子股票的ETF,则不太适合频繁交易,有能力的可以选择高增长行业的龙头股来做高频。
弊端
-
投资周期非常长,一般按年计;
-
收益率一般(年化8%左右),远比不上专业投资人,更不能和币圈相提并论;
-
资金流动性不好,长时间的熊市属于常态,卖出的窗口期很短;
-
投资风格非常保守,更偏向于理财,而非投资。
优点
-
完全属于被动投资,平时几乎不需要操心;
-
没有追涨杀跌,没有人性考验,可以天天睡得安稳;
-
熊市”播种”救企业于危难,牛市”分红”共享盛世繁华,政治正确,妥妥的正能量。
量化交易平台
普通的定投或是简单的智能定投策略,在支付宝上已经能很方便的操作了。作为码农,我们肯定希望更自主可控些,这里有更多的量化交易平台可供选择:
-
开源 vnpy
https://github.com/vnpy/vnpy
-
聚宽
https://www.joinquant.com/
-
米筐
https://www.ricequant.com/
-
优矿
https://uqer.datayes.com/
大多以 Python 为开发语言,对于习惯拿机器学习做数据分析的朋友非常友好,这里以聚宽为例。官网注册个账号,新建 Notebook 就能在线运行了,离线版本需要额外申请免费6个月试用。详细可以参考一下 API 文档。
https://www.joinquant.com/help/api/help#api:API文档
初始化
选择沪深300为基线,每月定投1万元,每次至少定投10个月才赎回,目标收益率为 20%。
# 导入函数库
from jqdata import *
# 初始化函数,设定基准等等
def initialize(context):
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 输出内容到日志 log.info()
log.info('初始函数开始运行且全局只运行一次')
# 过滤掉order系列API产生的比error级别低的log
# log.set_level('order', 'error')
### 股票相关设定 ###
# 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
# 要操作的基金:(g.为全局变量)
g.security = '510300.XSHG'
# 预期目标
g.goal = 1.2
# 均值窗口期
g.during = 500
# 定投基本值
g.base_order_value = 10000
# 卖出锁定周期
g.sell_period = 10
g.sell_timestamp = context.current_dt
run_monthly(market_open, monthday=1, reference_security='000300.XSHG')
均线策略
在每月无脑定投中,稍微加点策略:
高位少买
# 高位买入
def high_buy(security, base_order_value, cash, ratio):
# 默认扣款率
pay_ratio = 1
if ratio < 0.15:
pay_ratio = 0.9
elif ratio < 0.50:
pay_ratio = 0.8
elif ratio < 1:
pay_ratio = 0.7
else:
pay_ratio = 0.6
# 需买入的金额
order_value_cash = base_order_value*pay_ratio
log.info("%s: %f, cash: %d, ratio: %f"%(security, pay_ratio, cash, ratio))
if cash < order_value_cash:
log.info("现金 %d 不足, 买入失败 %s: %d " % (cash, security, order_value_cash))
return False
log.info("高位买入 %s: %d" % (security, order_value_cash))
order_value(security, order_value_cash)
return True
低位多买
# 低位买入
def low_buy(security, base_order_value, cash, ratio):
# 默认扣款率
pay_ratio = 1
# 近10天的最高价和最低价
value_range = get_bars(security, count=10, unit='1d', fields=['high','low'])
max_value = max(value_range['high'])
min_value = min(value_range['low'])
if (max_value - min_value)/max_value > 0.05:
# 大幅度震荡,持续下跌通道中
if ratio < 0.05:
pay_ratio = 0.6
elif ratio < 0.10:
pay_ratio = 0.7
elif ratio < 0.20:
pay_ratio = 0.8
elif ratio < 0.30:
pay_ratio = 0.9
elif ratio < 0.40:
pay_ratio = 1
else:
pay_ratio = 1.1
else:
# 小幅度震荡,形成底部加大购买量
if ratio < 0.5:
pay_ratio = 1.6
elif ratio < 0.10:
pay_ratio = 1.7
elif ratio < 0.20:
pay_ratio = 1.8
elif ratio < 0.30:
pay_ratio = 1.9
elif ratio < 0.40:
pay_ratio = 2
else:
pay_ratio = 2.1
# 需买入的金额
order_value_cash = base_order_value*pay_ratio
if cash < order_value_cash:
log.info("现金 %d 不足, 买入失败 %s: %d " % (cash, security, order_value_cash))
return False
log.info("低位买入 %s: %d" % (security, order_value_cash))
order_value(security, order_value_cash)
return True
预期止盈
这里为了回测方便,没法”听新闻”判断了,先以满足预期目标收益来止盈。
# 卖出
def sell(security, current_price, MA, sell_timestamp):
log.info("sell: %f, MA: %f" %(current_price, MA))
if current_price/MA < g.goal:
return False
if (sell_timestamp - g.sell_timestamp).days/30 < g.sell_period:
return False
# 卖出所有股票,使这只股票的最终持有量为0
log.info("%s, %s, %d" % (sell_timestamp, g.sell_timestamp, (sell_timestamp - g.sell_timestamp).days))
log.info("达到预期目标, 卖出 %s" % (security))
order_target(security, 0)
# 更新卖出时间戳
g.sell_timestamp = sell_timestamp
return True
运行策略
万事俱备,我们将上述函数都组合到一起,跑一下看看效果。
## 开盘时运行函数
def market_open(context):
log.info('函数运行时间(market_open):'+str(context.current_dt.time()))
security = g.security
# 平均值窗口期
during = g.during
# 获取股票的收盘价
close_data = get_bars(security, count=during, unit='1d', fields=['close'])
# 取得过去500天的平均价格
MA = close_data['close'].mean()
# 取得上一时间点价格
current_price = close_data['close'][-1]
# 取得当前的现金
cash = context.portfolio.available_cash
# 定投金额
base_order_value = g.base_order_value
if (current_price > MA):
# 高位卖出
sell(security, current_price, MA, context.current_dt)
# 高位少买
high_buy(security, base_order_value, cash, (current_price-MA)/MA)
else:
# 低位多买
low_buy(security, base_order_value, cash, (MA-current_price)/MA)
#得到本次所有成交记录
trades = get_trades()
for _trade in trades.values():
log.info('成交记录:'+str(_trade))
log.info('本轮结束')
log.info('##############################################################')
选择2015年到2021年来做回测,貌似看起来还不错,买入点很多,除了零星几次资金量用完,几乎每月都有交易;卖出点才4次,这一方面受限于“卖出锁定周期”,另一方面也体现A股长期熊市的现象。
年化收益 9.85%,这里小额定投的建仓周期比较长,所以相对资金利用率不够高,这里的仓位可以简单理解为最大投资规模。实际操作中,大家可以把固定收入作为资金投入,大额资金可以用作其他投资,扩大收益率。
再多选几个长周期,比如2017年至今,或是2019年至今,比不上牛市收益,但可以逃过股市熔断大跳水,大多时候收益率能保持稳定正值。
实盘交易
直接对接证券机构
-
模拟交易,手动操作
模拟交易
由于我们买入卖出操作不多,可以将制定好的策略,用模拟交易的方式将买入卖出信号通过微信消息来发送,再根据实际情况进行基金操作。
# 给微信发送消息(添加模拟交易,并绑定微信生效)
send_message("买入 %s: %d" % (security, order_value_cash))
总结
看到这里,相信搞深度学习的朋友肯定想拿手上一堆时序模型跃跃欲试了。先小泼盆冷水,就自我体验和身边做量化交易朋友的教训来看,单一模型在A股上基本没戏。
原因主要有以下几点:
-
时序模型基于历史趋势可再现,历史不会简单重复,只会换种形势卷土重来。
-
众多的量化机构让原有的“低风险策略点”稍纵即逝,寄生策略泛滥。
-
A股是强政策市,金融因素占比偏小。
-
散户比例很高,市场情绪化影响偏大。
另外,以上这些仅作为技术分享和个人经验之谈,不作为投资建议。更多的交易策略,等金融专业人士乱入指点。还有NLP舆情分析关键字拉涨停的更多骚操作,评论区打开脑洞吧。
论一个韭菜的自我修养,侠之大者,为国接盘。
哎,2021年说好的每周一更呢,感觉欠了很多的债。有鸿蒙系列的,树莓派系列的,OCR系列的,知识图谱系列的,手稿太多,没有心境慢慢整理,希望来年能补全。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/153174.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...