始终买入沪深300中市值最小的5只
先订阅000300分钟行情(也可订阅其他symbol,只是用来作行情触发)
第一个bar行情到来时在md_init中选股
选出股票池与持仓作对比
无持仓时直接按照股票池等权买入
有持仓时,不在股票池中的股票卖出
在成交回报on_order_filled中判断是否都已卖出,卖出仓位都成交以后再买入。
2. 代码解读:
2.1 Alpha.py
- # !/usr/bin/env python
- # -*- coding: utf-8 -*-
- from gmsdk.api import StrategyBase
- class Alpha(StrategyBase):
- def __init__(self, *args, **kwargs):
- super(Alpha, self).__init__(*args, **kwargs)
- self.buy_dict = {}
- self.sell_dict = {}
- self.is_traded = False
- def initialize(self):
- pass
- # 收到第一根Bar后交易
- def on_bar(self, bar):
- print(bar.strtime)
- if self.is_traded:
- return
- self.is_traded = True
- self.initialize()
- self.handle_data()
- def handle_data(self):
- pass
- def on_order_filled(self, order):
- if order.sec_id in self.sell_dict and order.strategy_id == self.strategy_id:
- self.sell_dict.pop(order.sec_id)
- if len(self.sell_dict) == 0: # 由于资金每次都开满,等卖盘全部成交资金回流时再买入
- cash = self.get_cash()
- for bar in self.buy_dict.values():
- vol = int(cash.available * 0.95 / len(self.buy_dict) / bar.close / 100) * 100
- self.open_long(bar.exchange, bar.sec_id, 0, vol)
- # !/usr/bin/env python
- # -*- coding: utf-8 -*-
- from Alpha import Alpha
- '''
- 请在Strategy中修改个人账号密码和策略ID
- '''
- class Strategy(Alpha):
- def __init__(self, *args, **kwargs):
- super(Strategy, self).__init__(*args, **kwargs)
- self.md.subscribe('SHSE.000300.bar.60') # 订阅一个symbol,在交易时间触发下单
- def initialize(self):
- # region 获取沪深300中当天可交易的股票
- instruments1 = self.get_instruments('SHSE', 1, 1)
- instruments2 = self.get_instruments('SZSE', 1, 1)
- symbol_list1 = set(instrument.symbol for instrument in instruments2 + instruments1) # 获取当日可交易的股票,剔除B股
- constituents = self.get_constituents('SHSE.000300')
- symbol_list2 = set(constituent.symbol for constituent in constituents) # 获取沪深300成分股(剔除ST、*ST股票,以及上市时间不足3个月等股票后剩余的股票)
- symbol_list = symbol_list1 & symbol_list2
- symbol_list = ','.join(symbol for symbol in symbol_list)
- # endregion
- # region 选出市值最小的5只
- market_index = self.get_last_market_index(symbol_list)
- data = [mi for mi in market_index]
- data = sorted(data, key=lambda mi: mi.market_value)[:5] # 市值最小的5只
- # endregion
- # region 为了计算仓位,获取昨日dailybar,存入buy_dict
- buy_list = ','.join(d.symbol for d in data)
- dailybars = self.get_last_dailybars(buy_list)
- self.buy_dict = {dailybar.sec_id: dailybar for dailybar in dailybars}
- # endregion
- def handle_data(self):
- # region 没有持仓时直接open_long
- print(self.buy_dict.keys())
- positions = self.get_positions()
- if len(positions) == 0:
- cash = self.get_cash()
- for b in self.buy_dict.values():
- vol = int(cash.available * 0.95 / len(self.buy_dict) / b.close / 100) * 100
- self.open_long(b.exchange, b.sec_id, 0, vol)
- return
- # endregion
- # region 有持仓时结合持仓获取buy_dict,sell_dict
- for p in positions:
- if p.sec_id in self.buy_dict:
- self.buy_dict.pop(p.sec_id)
- else:
- self.sell_dict[p.sec_id] = p
- # endregion
- for p in self.sell_dict.values(): # 先卖出,卖盘成交时再买入,若资金足够也可以直接买入
- self.close_long(p.exchange, p.sec_id, 0, p.volume)
- def on_order_status(self, order):
- pass
- if __name__ == '__main__':
- my_strategy = Strategy(
- username='username', # 请修改账号
- password='password', # 请修改密码
- strategy_id='strategy_id', # 请修改策略ID
- mode=2,
- td_addr='localhost:8001')
- ret = my_strategy.run()
- print('exit code: ', ret)
3.1 Python标准函数:
功能 | 函数原型 | 参数 | 返回值 | ||
参数名 | 含义 | ||||
join | 连接字符串数组。将字符串、元组、列表中的元素以指定的字符(分隔符)连接生成一个新的字符串 | 'sep'.join(seq) | sep | 分隔符。可以为空 | 返回一个以分隔符sep连接各个元素后生成的字符串 |
seq | 要连接的元素序列、字符串、元组、字典 | ||||
sorted | 排序 | sorted(iterable, cmp=None, key=None, reverse=False) | iterable | iteralbe指的是能够一次返回它的一个成员的对象。iterable主要包括3类: 第一类是所有的序列类型,比如list(列表)、str(字符串)、tuple(元组)。 第二类是一些非序列类型,比如dict(字典)、file(文件)。 第三类是你定义的任何包含__iter__()或__getitem__()方法的类的对象。 | |
cmp | cmp: 指定一个定制的比较函数,这个函数接收两个参数(iterable的元素),如果第一个参数小于第二个参数,返回一个负数;如果第一个参数等于第二个参数,返回零;如果第一个参数大于第二个参数,返回一个正数。默认值为None。 | ||||
key | key:指定一个接收一个参数的函数,这个函数用于从每个元素中提取一个用于比较的关键字。默认值为None。 | ||||
reverse | reverse:是一个布尔值。如果设置为True,列表元素将被降序排列,默认为升序排列。 通常来说,key和reverse比一个等价的cmp函数处理速度要快。这是因为对于每个列表元素,cmp都会被调用多次,而key和reverse只被调用一次。 |
[tr][/tr]
功能 | 函数原型 | 参数 | 返回值 | |||
参数名 | 类型 | 说明 | ||||
get_instruments | 提取交易代码。策略类和行情服务类都提供该接口。 | get_instruments(exchange, sec_type, is_active) | exchange | string | 交易所代码 | Instrument对象列表 |
sec_type | int | 代码类型:1.股票,2.基金,3.指数,4.期货,5.ETF | ||||
is_active | int | 当天是否交易:1.是,0.否 | ||||
get_constituents | 提取指数的成分股代码。策略类和行情服务类都提供该接口。 | get_constituents(index_symbol) | index_symbol | string | 指数代码 | constituent对象列表 |
get_last_market_index | 按时间周期提MarketIndex,按时间升序排列。策略类和行情服务类都提供该接口。 | get_last_market_index(symbol_list) | symbol_list | string | 多个品种代码列表,如SHSE.600000,SZSE.000001 | MarketIndex对象列表 |
get_last_dailybars | 提取最新1条DailyBar数据,支持单个代码提取或多个代码组合提取。策略类和行情服务类都提供该接口。 | get_last_dailybars(symbol_list) | symbol | string | 证券代码, 带交易所代码以确保唯一,如SHSE.600000,同时支持多只代码 | DailyBar列表 |
get_positions | 查询当前策略指定symbol(由交易所代码和证券ID组成)和买卖方向的持仓信息。策略类和交易服务类都提供该接口。 | get_position(exchange, sec_id, side); | exchange | string | 交易所代码 | Position对象,持仓信息 |
sec_id | string | 证券代码 | ||||
side | int | 买卖方向 | ||||
get_cash | 查询当前策略的资金信息,策略类和交易服务类都提供该接口。 | get_cash() | 无 | Cash对象,当前策略的资金信息 | ||
open_long | 异步开多仓,以参数指定的symbol、价和量下单。如果价格为0,为市价单,否则为限价单。策略类和交易服务类都提供该接口 | open_long(exchange, sec_id, price, volume) | exchange | string | 交易所代码, 如上交所SHSE | 委托下单生成的Order对象 |
sec_id | string | 证券代码,如浦发银行600000 | ||||
price | float | 委托价,如果price=0,为市价单,否则为限价单 | ||||
volume | float | 委托量 | ||||
close_long | 异步平多仓接口,以参数指定的exchange, 证券代码sec_id, 价和量下单。如果价格为0,为市价单,否则为限价单。策略类和交易服务类都提供该接口。 | close_long(exchange, sec_id, price, volume) | exchange | string | 交易所代码, 如上交所SHSE | 委托下单生成的Order对象 |
sec_id | string | 证券代码,如浦发银行600000 | ||||
price | float | 委托价,如果price=0,为市价单,否则为限价单 | ||||
volume | float | 平仓量 |
4. 金融术语:
阿尔法策略:投资者在市场交易中面临着系统性风险(即贝塔或Beta、β风险)和非系统性风险(即阿尔法或Alpha、α风险),通过对系统性风险进行度量并将其分离,从而获取超额绝对收益(即阿尔法收益)的策略组合,即为阿尔法策略。从广义上讲,获取阿尔法收益的投资策略有很多种,其中既包括传统的基本面分析选股策略、估值策略、固定收益策略等等,也包括利用衍生工具对冲掉贝塔风险、获取阿尔法收益的可转移阿尔法策略。后者在国内通常被称为阿尔法对冲策略,并在近年A股市场上得到广泛应用。本策略只是展示了选股策略,并没有将贝塔风险对冲。