
搭建自己的量化系统

股票量化交易系统QTYX是一个即可以用于学习,也可以用于实战炒股分析的系统。






整体的设计框架如下图所示。
操作上,要在主界面上更新股票数据和选择选股策略。操作方法可参照使用攻略中对应专题。
执行选股时采用多任务方案,每个任务中注册了相应的策略,股票数据会分发给这些任务,每个任务独立选股,最后合并为一份选股结果。
选股结果出来后,还可以叠加一些特殊数据进行多方位条件选股,比如财务数据、基金持仓数据、基本面数据等等。


接下来介绍下如何添加策略代码。
首先找到文件“QTYX/StrategyGath/PattenGath.py”,根据统一格式添加一个自己的策略函数,比如名称“user_define_strategy”,然后在函数中用Python添加自己的策略逻辑,如下代码所示:(编写策略代码时,请注意传入参数的格式和内容,以及返回数据的格式,以兼容这个系统框架)
此处,我们编写的策略逻辑是M5M10M20三条均线呈多头排列,同时KDJ的J指标大于100,当个股持续3个交易日都满足两个叠加的条件的时候,过滤出这个股票。
def user_define_strategy(name, code, stock_data, patlog_obj, **kwargs):
"""
# 输入参数
:param name: 股票名称, 平安银行
:param code: 股票代码, 000001.SZ
:param stock_data: 股票数据, DataFrame格式
:param patlog_obj: 打印日志接口
:param kwargs: dict: 配置参数, 可以直接在函数中修改
:return:
"""
try:
df_search = pd.DataFrame() # 构建一个空的dataframe用来装数据
MA1 = stock_data["收盘价"].rolling(window=5).mean() # 计算M日的移动平均线
MA2 = stock_data["收盘价"].rolling(window=10).mean() # 计算M日的移动平均线
MA3 = stock_data["收盘价"].rolling(window=20).mean() # 计算M日的移动平均线
CLOSE = stock_data["收盘价"]
MA1.fillna(0, inplace=True)
MA2.fillna(0, inplace=True)
MA3.fillna(0, inplace=True)
# 循环判断是否连续N日都符合均线多头排列的特征
for id_a in range(0, 4):
T = (CLOSE[-1 - id_a] > MA1[-1 - id_a] > MA2[-1 - id_a] > MA3[-1 - id_a])
if T != True: break # 只要有一天不满足则退出
low_list = stock_data['最低价'].rolling(9, min_periods=1).min()
high_list = stock_data['最高价'].rolling(9, min_periods=1).max()
rsv = (stock_data['收盘价'] - low_list) / (high_list - low_list) * 100
stock_data['K'] = rsv.ewm(com=2, adjust=False).mean()
stock_data['D'] = stock_data['K'].ewm(com=2, adjust=False).mean()
stock_data['J'] = 3 * stock_data['K'] - 2 * stock_data['D']
# 循环判断是否连续N日J的值都大于100
for id_b in range(0, 4):
T = (stock_data['J'][-1 - id_b] > 100)
if T != True: break # 只要有一天不满足则退出
if (id_a >= 3 and id_b >= 3):
# 输出满足要求的股票
patlog_obj.re_print("符合特征: 股票 {},代码 {}".format(name, code))
df_search = pd.DataFrame([[name, code]], index=[0], columns=["股票名称", "股票代码"])
return df_search
except Exception as e:
print(e)
return pd.DataFrame()
编写完策略后,需要把策略注册到选股框架中。先是在界面中注册。找到文件“QTYX/MainlyGui/ElementGui/DefDialogs/ParaDialog.py”, SelectModeDialog类的“self.patten_type_cmbo”变量中添加一个策略名称,比如“自定义策略-DIY学习”。如以下代码所示:
class SelectModeDialog(wx.Dialog): # 形态选股参数/更新行情数据参数/RPS选股参数
def __init__(self, parent, title=u"形态选股参数配置", size=(750, 200)):
pass
def patten_dialog(self, sizer_object):
# 中间代码已省略
# 形态选股参数——形态类型选取
self.patten_type_box = wx.StaticBox(self, -1, u'选股模型')
self.patten_type_sizer = wx.StaticBoxSizer(self.patten_type_box, wx.HORIZONTAL)
self.patten_type_cmbo = wx.ComboBox(self, -1, choices=["主升浪(均线多头&突破前高)", "双底形态突破", "箱体形态突破", "单针探底回升",
"自定义策略-DIY学习", "线性回归-预留"],
style=wx.CB_READONLY | wx.CB_DROPDOWN) # 选股项
添加完成后,在界面中会看到对应得选项,如下图所示:
然后在选股框架中注册。找到文件“QTYX/MainlyGui/UserFrame.py”,在“patten_analy_execute”函数的“register_info”变量中添加刚才创建的策略名称,记得要界面中的名称和函数名称一一对应。如以下代码所示:
def patten_analy_execute(self, stock_code):
register_info = {"双底形态突破": Base_Patten_Group.double_bottom_search,
"箱体形态突破": Base_Patten_Group.bottom_average_break,
"单针探底回升": Base_Patten_Group.needle_bottom_raise,
"主升浪(均线多头&突破前高)": Base_Patten_Group.main_rise_wave,
"自定义策略-DIY学习": Base_Patten_Group.user_define_strategy,
}
# 中间代码已省略
return df_return # 有效则添加至分析结果文件中
另外,每个策略都有它的算法参数,需要创建一个填写参数的对话框。找到文件“QTYX/MainlyGui/ElementGui/DefDialogs/SpecDialog.py”,添加一个对话框类,比如名称“UserDefStrategyDialog”。如果是自己使用,并且参数已经确定了,可以直接在策略代码中固定参数值,界面只需要留一个空壳即可,这样更简单点。如下代码所示:
class UserDefStrategyDialog(wx.Dialog): # 用户自定义参数界面
def __init__(self, parent, title=u"自定义提示信息", size=(500, 360)):
wx.Dialog.__init__(self, parent, -1, title, size=size, style=wx.DEFAULT_FRAME_STYLE)
# 中间代码已省略
# 创建FlexGridSizer布局网格
# rows 定义GridSizer行数
# cols 定义GridSizer列数
# vgap 定义垂直方向上行间距
# hgap 定义水平方向上列间距
self.FlexGridSizer = wx.FlexGridSizer(rows=1, cols=2, vgap=0, hgap=0)
self.ok_btn = wx.Button(self, wx.ID_OK, u"确认")
self.ok_btn.SetDefault()
self.cancel_btn = wx.Button(self, wx.ID_CANCEL, u"取消")
self.FlexGridSizer.Add(self.ok_btn, proportion=1, border=1, flag=wx.ALL | wx.EXPAND)
self.FlexGridSizer.Add(self.cancel_btn, proportion=1, border=1, flag=wx.ALL | wx.EXPAND)
self.FlexGridSizer.SetFlexibleDirection(wx.BOTH)
self.SetSizerAndFit(self.FlexGridSizer)
self.Centre()
def feedback_paras(self):
self.user_para = dict()
return self.user_para
接下来在文件“QTYX/MainlyGui/UserFrame.py”中,把对话框函数“UserDefStrategyDialog”导入进去。如下代码所示:
from MainlyGui.ElementGui.DefDialogs.SpecDialog import UserDefStrategyDialog
接下来在文件“QTYX/MainlyGui/UserFrame.py”中,找到事件函数“_ev_patten_select_func”,把对话框函数“UserDefStrategyDialog”注册进去,记得要界面中的名称和函数名称一一对应。
def _ev_patten_select_func(self, event):
pass
register_info = {"主升浪(均线多头&突破前高)":{"对话框函数": MainRiseWaveDialog,
"日志信息":"主升浪形态选股正在执行..."},
"双底形态突破": {"对话框函数": DouBottomDialog,
"日志信息":"双底形态选股正在执行..."},
"箱体形态突破":{"对话框函数": BreakBottomDialog,
"日志信息":"底部形态选股正在执行..."},
"单针探底回升": {"对话框函数": NeedleBottomDialog,
"日志信息": "单针探底回升选股正在执行..."},
"自定义策略-DIY学习":{"对话框函数": UserDefStrategyDialog,
"日志信息": "单针探底回升选股正在执行..."}
}
pass
最后生成选股结果时,如果想要叠加特色数据,就在文件“QTYX/MainlyGui/UserFrame.py”中,找到函数“patten_analy_result”,把特色数据叠加到形态选股文件中即可。
def patten_analy_result(self):
pass
if self.patten_paras[u"北向资金持股"] == True:
pass
if self.patten_paras[u"每日基本面指标"] == True:
pass
if self.patten_paras[u"叠加利润报表"] == True:
pass
Base_File_Oper.save_csv_file(df_search, f"全市场选股结果/{self.patten_paras['选股模型']}分析结果_{select_date.strftime('%Y-%m-%d')}_高速版.csv")
self.patlog.re_print("\n形态分析完成!明细查看路径ConfigFiles/全市场选股结果/")
想要叠加的特色数据类别是在选股配置界面上勾选的,也是在“QTYX/MainlyGui/ElementGui/DefDialogs/ParaDialog.py”的“SelectModeDialog”类中修改。


接下来我们看下这个自定义策略的选股结果。
我们针对于近期比较热门的板块进行选股。
以下就是自定义策略的选股结果。
我们可以借助同花顺软件来对比下选股结果是否满足我们编写的算法。
用我们自己设计的策略选出来的个股,是否具有赚钱效应呢?我们还可以对结果进行回测评估,具体可以参照以下文章:
量化系统QTYX使用攻略|“回测评估”篇——选股策略赚不赚钱,上帝视角一目了然(更新2.8.1)


以上就是在QTYX系统中添加自己的选股策略的方法,例程代码会体现在2.8.3版本中,以供大家参考和学习。在调试过程中难免不会一帆风顺,大家记得多使用print打印日志,排查问题,祝愿各位早日搭建出属于自己的量化系统!
发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/105918
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!