碎碎念
心心念念的量化决策念叨了好久,前段时间终于把excel版的决策模板做出来了,但是一遍遍手动录入市价数据太繁琐,这周利用闲暇学习python,终于写出了自己的第一段量化决策代码。
没有图的道理都是耍流氓,话不多说,上图!
平台选择
前期简单了解了一下,目前国内主流的量化平台如下:
- 优矿(Uqer)
- 万矿(Wind Quant)
- 聚宽(JoinQuant)
- BigQuant
- 文华财经
- 同花顺Mind Go
- 米筐(RiceQuant)
- 掘金量化
优矿是最早做的,但是近一年社区没那么活跃了;
万矿依托国内最强大的金融数据端wind提供数据支持;
聚宽社区挺活跃的,但是用了几天感觉用户体验不太好,尤其是新手接入这块儿存在断层。
思虑再三,决定从万矿入手,毕竟有wind的数据支持,数据可靠性还是很有保证的。
设计思路
小插曲
因为上周五刚接触python,对这块还不够熟悉,加之对pandas、numpy等数据操作库的生疏,决定从excel开始构建数据,而非在python中从0开始捏数据。
之前设计的excel模板有些不适合代码读取后提取有用信息,故做了简单的整理改造,改造后各表结构如下:
整体思路:
- 读取excel,提取各表数据
- 根据'标的池'表代码,查询各标的最新 市价
- 结合'标的持仓'表持仓数,计算最新 持仓市值
- 根据持仓情况,计算 当前仓位
- 结合当前仓位、目标仓位和'调仓参数'表的配置,计算 动态仓位
- 根据调仓参数表的可分配资金和持仓市值计算 可分配价值
- 根据可分配价值和动态仓位确定 目标市值
- 再借此计算 价值偏移、应调仓数 和 调仓金额
代码实现
- 引入万矿依赖并建立连接
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 引入万矿依赖并建立连接
from WindPy import *
w.start(show_welcome = False)
- 引入pandas依赖,用以数据处理
# 引入pandas依赖,用以数据处理
import pandas as pd
- 定义持仓处理函数:获取市价,计算最新持仓市值
# 处理持仓
def work_flow1(stockpool,positions):
codes=stockpool['代码'].tolist()
# 获取行情
error,prices=w.wsq(codes, 'rt_last', "func=DemoWSQCallback", usedf=True)
assert error ==0 , "API数据提取错误,ErrorCode={},具体含义请至帮助文档附件《常见API错误码》中查询。".format(error)
# 行情数据处理:拼接市价、计算持仓市值
positions=pd.merge(positions,prices,left_on='代码', right_index=True, how='left')
positions['市价']=positions.pop('RT_LAST')
positions['持仓市值'] = positions.apply(lambda r: round(r['市价'] * r['持仓数']),axis=1)
return positions
- 定义决策处理函数:根据持仓情况和调仓配置,作出调仓决策
# 处理决策
def work_flow2(positions,param,decision):
market_cap = positions['持仓市值'].sum() # 持仓市值合计
step = param.loc[param['名称'] == '调整步数']['值'].iloc[0] # 分步数
amt = param.loc[param['名称'] == '当次投入额']['值'].iloc[0] # 手头现金
value_cap=market_cap+amt # 可支配价值
print('持仓市值合计:%d,可支配价值:%d' % (market_cap,value_cap))
def action(row):
pos = positions.loc[positions['代码'] == row['代码']].iloc[0]
row['当前仓位'] = round(pos['持仓市值'] / value_cap, 4)
row['动态仓位'] = round(row['当前仓位'] + (row['目标仓位'] - row['当前仓位']) / step, 4)
# 目标市值
tar_value = row['动态仓位'] * value_cap
row['价值偏移'] = round((pos['持仓市值'] - tar_value) / tar_value, 4)
row['应调仓数'] = round((tar_value - pos['持仓市值']) / pos['市价'], -2)
row['调仓金额'] = round(row['应调仓数'] * pos['市价'], 2)
return row
decision=decision.apply(action,axis=1)
return decision
- 编排工作流并执行
# 工作流
def work_flow():
# 定义文件路径和表名
data_from='data/榜单应用模板20200424.xlsx'
stockpool_sheet='标的池'
positions_sheet='标的持仓'
param_sheet='调仓参数'
decision_sheet='调仓决策'
# 读取模板excel
stockpool = pd.read_excel (data_from, sheet_name = stockpool_sheet)
positions = pd.read_excel (data_from, sheet_name = positions_sheet)
param = pd.read_excel (data_from, sheet_name = param_sheet)
decision = pd.read_excel (data_from, sheet_name = decision_sheet)
# 处理持仓数据
positions=work_flow1(stockpool,positions)
# 处理决策
decision=work_flow2(positions,param,decision)
print('完成工作流!')
return stockpool,positions,param,decision
# 执行工作流
df=work_flow()
- 展示持仓情况
# 持仓
from WindCharts import *
# 数据显示
WTable(data=df[1]).plot()
- 展示决策情况
# 决策结果
from WindCharts import *
# 数据显示
WTable(data=df[3]).plot()
- 为了直观地分析持仓分布,定义了柱状图和饼状图
# 持仓柱状图
import matplotlib.pyplot as plt
def draw_bar(positions):
names=positions['名称'].tolist()
values=positions['持仓市值'].tolist()
plt.bar(names,values)
plt.xticks(rotation=90)
draw_bar(df[1])
# 持仓饼图
import matplotlib.pyplot as plt
def draw_pie(positions):
positions=positions.loc[positions['持仓市值'] != 0,:].sort_values('持仓市值')
names=positions['名称'].tolist()
values=positions['持仓市值'].tolist()
fig = plt.figure(facecolor='#f1f5f5')
ax=plt.axes([0,0,1.6,1.6])
patches,l_text,p_text=ax.pie(values,labels=names,autopct='%1.2f%%',startangle=90)
for t in l_text: t.set_size(20)
for t in p_text: t.set_size(18)
draw_pie(df[1])
Ending
项目地址:https://gitee.com/stephenshen/ark-quant/tree/master/first-quant
可以直接导入到万矿
记得上传数据表到指定位置
转载请注明出处:https://www.jianshu.com/p/b973a5f56213
谢谢~