楼主: 唉人好累66
2235 3

[交易策略] [干货分享】从零开始学量化:01因子选股策略 [推广有奖]

  • 0关注
  • 41粉丝

讲师

55%

还不是VIP/贵宾

-

威望
1
论坛币
1457 个
通用积分
5.0477
学术水平
11 点
热心指数
14 点
信用等级
11 点
经验
3660 点
帖子
214
精华
0
在线时间
119 小时
注册时间
2016-9-24
最后登录
2020-4-8

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币
1. 策略原理及伪代码:
     1.1 策略原理
始终买入PE最小的1000只股票中市值最小的5只;
无持仓时直接按照股票池等权买入;
有持仓时,不在股票池中的股票卖出。

     1.2 策略伪代码
策略逻辑用伪代码描述如下:
- -初始化部分逻辑:
  功能说明:生成当天的持仓代码列表,并获取昨天的日线数据,方便计算仓位
  操作步骤:
    1. 获取当天可交易的沪深股票A股代码
    2. 获取指数'SHSE.000985'的所有成份股
    3. 取两者交集,生成股票代码列表
    4. 取出上述代码列表中的PE值
    5. 基于PE值过滤,生成当天的持仓代码列表
          -  剔除PE为负的股票代码
          -  筛选出PE值最小的1000只股票代码,需要先按PE排序
          -  在上述结果中,再挑选出市值最小的5只股票,生成当天的持仓代码列表。
   6. 为了开盘后触发交易,订阅一个指数‘SHSE.000016’的分钟Bar数据

- -交易部分逻辑:
  功能说明: 因为基于日线数据计算,在开盘收到第一条指数行情Bar数据后,就开始下单交易,完成持仓调整。
  操作步骤:
      1.   查询已有持仓数据
      2.  根据目标持仓对已有持仓进行调整:
            a. 当前没有持仓时,按95%仓位规划,等资金量买入目标持仓中的股票。
            b. 当前有持仓时,检查已有仓位:
                    如果已持有股票,不在目标持仓中的,直接卖出。
                    如果已持有股票也在目标持仓中,不再重复买。
基于上述逻辑生成卖出列表和新的买入列表。
对卖出列表立即执行。
       3.  在卖出列表执行完成,资金回流可用后,执行买入列表。  
             -  订阅委托完全成交事件,在每次完全成交事件处理中,从卖出列表中清除相应股票代码
             -  然后检查卖出列表是否已清空,如果是,表明股票已经全部卖出完毕,执行买入列表。   否则,继续等待。


  1. # !/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. from gmsdk.api import StrategyBase
  4. '''
  5. 请在Strategy中修改个人账号密码和策略ID
  6. '''
  7. class Strategy(StrategyBase):
  8.     def __init__(self, pe_len = 1000, mv_len = 5, *args, **kwargs):
  9.         super(Strategy, self).__init__(*args, **kwargs)
  10.         self.pe_len = pe_len
  11.         self.mv_len = mv_len
  12.         self.buy_dict = {}
  13.         self.sell_dict = {}
  14.         self.is_traded = False

  15.         self.md.subscribe('SHSE.000016.bar.60') # 订阅一个行情,在交易时间触发下单

  16.     def md_init(self):
  17. # region 获取中证全指中当天可交易的股票
  18.         instruments1 = self.get_instruments('SHSE', 1, 1)
  19.         instruments2 = self.get_instruments('SZSE', 1, 1)
  20.         symbol_list1 = set(instrument.symbol for instrument in instruments2 + instruments1 if instrument.symbol[5] not in ['2', '9']) #获取当日可交易的股票,剔除B股
  21.         constituents = self.get_constituents('SHSE.000985')
  22.         symbol_list2 = set(constituent.symbol for constituent in constituents)#获取中证全指成分股(剔除ST、*ST股票,以及上市时间不足3个月等股票后剩余的股票)
  23.         symbol_list = symbol_list1 & symbol_list2
  24.         symbol_list = ','.join(symbol for symbol in symbol_list)
  25. # endregion

  26. # region 选出PE最小的1000只中市值最小的5只
  27.         market_index = self.get_last_market_index(symbol_list)
  28.         data = list(mi for mi in market_index if mi.pe_ratio > 0) # 剔除PE为负的股票
  29.         data = sorted(data, key= lambda mi: mi.pe_ratio)[:self.pe_len] # PE最小的1000只
  30.         data = sorted(data, key= lambda mi: mi.market_value)[:self.mv_len] # 市值最小的5只
  31. # endregion

  32. # region 为了计算仓位,获取昨日dailybar,存入buy_dict
  33.         buy_list = ','.join(d.symbol for d in data)
  34.         dailybars = self.get_last_dailybars(buy_list)
  35.         self.buy_dict = dict((dailybar.sec_id, dailybar) for dailybar in dailybars)
  36.         # endregion

  37.     # 收到第一根Bar后交易
  38.     def on_bar(self, bar):
  39.         print(bar.strendtime[:-6].replace('T', ' '))
  40.         if self.is_traded:
  41.             return
  42.         self.is_traded = True
  43.         self.md_init()

  44. # region 没有持仓时直接open_long
  45.         print(self.buy_dict.keys())
  46.         positions = self.get_positions()
  47.         if len(positions) == 0:
  48.             cash = self.get_cash()
  49.             for b in self.buy_dict.values():
  50.                 order = self.open_long(b.exchange, b.sec_id, 0, int(cash.available * 0.95 / len(self.buy_dict) / b.close / 100) * 100)
  51.             return
  52. # endregion

  53. # region 有持仓时结合持仓获取buy_dict,sell_dict
  54.         for p in positions:
  55.             if p.sec_id in self.buy_dict:
  56.                 self.buy_dict.pop(p.sec_id)
  57.             else:
  58.                 self.sell_dict[p.sec_id] = p
  59.         # endregion

  60.         for p in self.sell_dict.values(): # 先卖出,卖盘成交时再买入,若资金足够也可以直接买入
  61.             self.close_long(p.exchange, p.sec_id, 0, p.volume)

  62.     def on_order_filled(self,order):
  63.         if order.sec_id in self.sell_dict and order.strategy_id == self.strategy_id:
  64.             self.sell_dict.pop(order.sec_id)
  65.             if len(self.sell_dict) == 0:#由于资金每次都开满,等卖盘全部成交资金回流时再买入
  66.                 cash = self.get_cash()
  67.                 for bar in self.buy_dict.values():
  68.                     self.open_long(bar.exchange, bar.sec_id, 0, int(cash.available * 0.95 / len(self.buy_dict) / bar.close / 100) * 100)

  69. if __name__ == '__main__':
  70.     my_strategy = Strategy(
  71.         username='username', # 请修改账号
  72.         password='password', # 请修改密码
  73.         strategy_id='strategy_id', # 请修改策略ID
  74.         mode=3,
  75.         td_addr='localhost:8001')
  76.         ret = my_strategy.run()
  77.          print('exit code: ', ret)
复制代码


3. Python相关函数
    3.1 Python标准函数:
功能函数原型参数返回值
参数名含义
join连接字符串数组。将字符串、元组、列表中的元素以指定的字符(分隔符)连接生成一个新的字符串'sep'.join(seq)sep分隔符。可以为空返回一个以分隔符sep连接各个元素后生成的字符串
seq要连接的元素序列、字符串、元组、字典
list将元组转换为列表。
注:元组与列表是非常类似的,区别在于元组的元素值不能修改,元组是放在括号中,列表是放于方括号中。
list( seq )seq要转换为列表的元祖返回列表
sorted排序sorted(iterable, cmp=None, key=None, reverse=False)iterableiteralbe指的是能够一次返回它的一个成员的对象。iterable主要包括3类:        第一类是所有的序列类型,比如list(列表)、str(字符串)、tuple(元组)。         第二类是一些非序列类型,比如dict(字典)、file(文件)。        第三类是你定义的任何包含__iter__()或__getitem__()方法的类的对象。
cmpcmp: 指定一个定制的比较函数,这个函数接收两个参数(iterable的元素),如果第一个参数小于第二个参数,返回一个负数;如果第一个参数等于第二个参数,返回零;如果第一个参数大于第二个参数,返回一个正数。默认值为None。
keykey:指定一个接收一个参数的函数,这个函数用于从每个元素中提取一个用于比较的关键字。默认值为None。
reversereverse:是一个布尔值。如果设置为True,列表元素将被降序排列,默认为升序排列。         通常来说,key和reverse比一个等价的cmp函数处理速度要快。这是因为对于每个列表元素,cmp都会被调用多次,而key和reverse只被调用一次。
   3.2 掘金接口函数:
[tr][/tr]
功能函数原型参数返回值
参数名类型说明
md_init初始化行情接口md.init("your user name", "your password")your user namestring用户名
your passwordstring密码
get_instruments提取交易代码。策略类和行情服务类都提供该接口。get_instruments(exchange, sec_type, is_active)exchangestring交易所代码Instrument对象列表
sec_typeint代码类型:1.股票,2.基金,3.指数,4.期货,5.ETF
is_activeint当天是否交易:1.是,0.否
get_constituents提取指数的成分股代码。策略类和行情服务类都提供该接口。get_constituents(index_symbol)index_symbolstring指数代码constituent对象列表
get_last_market_index按时间周期提MarketIndex,按时间升序排列。策略类和行情服务类都提供该接口。get_last_market_index(symbol_list)symbol_liststring多个品种代码列表,如SHSE.600000,SZSE.000001MarketIndex对象列表
get_last_dailybars提取最新1条DailyBar数据,支持单个代码提取或多个代码组合提取。策略类和行情服务类都提供该接口。get_last_dailybars(symbol_list)symbolstring证券代码, 带交易所代码以确保唯一,如SHSE.600000,同时支持多只代码DailyBar列表
get_positions查询当前策略指定symbol(由交易所代码和证券ID组成)和买卖方向的持仓信息。策略类和交易服务类都提供该接口。get_position(exchange, sec_id, side);exchangestring交易所代码Position对象,持仓信息
sec_idstring证券代码
sideint买卖方向
get_cash查询当前策略的资金信息,策略类和交易服务类都提供该接口。get_cash()Cash对象,当前策略的资金信息
on_bar响应Bar事件,收到Bar数据后本函数被调用。on_bar(bar)barbarbar数据
open_long异步开多仓,以参数指定的symbol、价和量下单。如果价格为0,为市价单,否则为限价单。策略类和交易服务类都提供该接口open_long(exchange, sec_id, price, volume)exchangestring交易所代码, 如上交所SHSE委托下单生成的Order对象
sec_idstring证券代码,如浦发银行600000
pricefloat委托价,如果price=0,为市价单,否则为限价单
volumefloat委托量
close_long异步平多仓接口,以参数指定的exchange, 证券代码sec_id, 价和量下单。如果价格为0,为市价单,否则为限价单。策略类和交易服务类都提供该接口。close_long(exchange, sec_id, price, volume)exchangestring交易所代码, 如上交所SHSE委托下单生成的Order对象
sec_idstring证券代码,如浦发银行600000
pricefloat委托价,如果price=0,为市价单,否则为限价单
volumefloat平仓量
to_dict类型转换函数,将GMSDK内置类型对象转换为dict对象; 使用前从gmsdk引入,即from gmsdk import to_dict。to_dict(obj)objobjectGMSDK内置类型对象dict对象
4. 金融术语:
市盈率(PE):某种股票每股市价与每股盈利(EPS)的比率。而EPS方面,若按已公布的上年度EPS计算,称为历史市盈率(historical P/E);计算预估市盈率所用的EPS预估值,一般采用市场平均预估(consensus estimates),即追踪公司业绩的机构收集多位分析师的预测所得到的预估平均值或中值。市场广泛谈及市盈率通常指的是静态市盈率,通常用来作为比较不同价格的股票是否被高估或者低估的指标。

市值:市值是指一家上市公司的发行股份按市场价格计算出来的股票总价值,其计算方法为每股股票的市场价格乘以发行总股数。整个股市上所有上市公司的市值总和,即为股票总市值


二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:从零开始 Instruments Instrument historical positions

沙发
唉人好累66 发表于 2017-7-25 15:42:38 |只看作者 |坛友微信交流群
后续还会继续上干货策略,好东西希望和大家一起分享,如果想了解更多精彩的量化方面的内容进入证经社——http://zjshe.cn/q/forum.php?gid=36了解更多吧~

使用道具

藤椅
kk5526682 发表于 2017-7-28 10:50:16 |只看作者 |坛友微信交流群
支持干货分享!!!大神既视感,哈哈

使用道具

板凳
唉人好累66 发表于 2017-7-28 11:04:01 |只看作者 |坛友微信交流群
kk5526682 发表于 2017-7-28 10:50
支持干货分享!!!大神既视感,哈哈
还会分享这一系列的~一起努力!!

使用道具

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注jr
拉您进交流群

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2024-4-23 22:00