海龟交易入市法则:系统 1:以 20 日突破为基础的短期 系统;系统 2:以 55 日突破为基础的中长期系统; 海龟交易退出法则:系统 1 采用 10 日突破退出法则: 对于多头头寸而言,在价格跌破过去 10 日最低点时退出;对 空头头寸而言,在价格超过 10 日最高点时退出。总之,如果 价格发生了不利于头寸的 10 日突破,所有单位头寸都要退出。 系统 2 采用 20 日突破退出法则:对多头头寸而言,是 20 日向 下突破,对空头头寸而言,是 20 日向上突破。只要价格发生 了不利于头寸的 20 日突破,所有头寸都会退出。
本策略只是海龟策略的框架:采用20日突破原则,20日向上突破时进行开仓,20日向下突破时进行平仓。
2. 代码解读:
2.1 turtle.ini
- [strategy]
- username=
- password=
- ;模拟状态
- mode=4
- td_addr=localhost:8001
- strategy_id=
- ;订阅代码注意及时更新
- subscribe_symbols=
- [backtest]
- start_time=2016-08-22 09:00:00
- end_time=2016-08-26 16:00:00
- ;策略初始资金
- initial_cash=1000000
- ;委托量成交比率,默认=1(每个委托100%成交)
- transaction_ratio=1
- ;手续费率,默认=0(不计算手续费)
- commission_ratio=0
- ;滑点比率,默认=0(无滑点)
- slippage_ratio=0
- [para]
- csv_file=stocks.csv
- period=20
- hop=0.1
- ##############################################################
- # logger settings
- ##############################################################
- [loggers]
- keys=root
- [logger_root]
- level=DEBUG
- handlers=console,file
- [handlers]
- keys=console,file
- [handler_file]
- class=handlers.RotatingFileHandler
- args=('strategy_turtle.log','a',1000,5)
- formatter=simple
- [handler_console]
- class=StreamHandler
- args = (sys.stdout,)
- formatter=simple
- [formatters]
- keys = simple
- [formatter_simple]
- format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
- datefmt=
- # encoding: utf8
- import logging
- import logging.config
- import pandas as pd
- import numpy as np
- from gmsdk import *
- class TurtleStrategy(StrategyBase):
- def __init__(self, *args, **kwargs):
- super(TurtleStrategy, self).__init__(*args, **kwargs)
- self.__get_param__()
- self.__init_data__()
- ;读取参数
- def __get_param__(self):
- self.csv_file = self.config.get('para', 'csv_file')
- self.period = self.config.getint('para', 'period')
- self.hop = self.config.get('para', 'hop') or 0.1
- ;读取CSV文件
- def __init_data__(self):
- '''
- read stocks from csv file
- :return:
- '''
- self.sec_ids = []
- self.hist_data = dict()
- self.positions = dict()
- subscribe_symbols = []
- stocks = pd.read_csv(self.csv_file, sep=',')
- for r in stocks.iterrows():
- exchange = r[1][0]
- sec_id = r[1][1]
- buy_amount = r[1][2]
- t = "{0}.{1}".format(exchange, sec_id)
- hl = self.get_highest_lowest_price(t)
- #print (hl)
- self.hist_data[t] = hl + (buy_amount,) ## high, low, buy_amount
- self.sec_ids.append("{0}".format(sec_id))
- subscribe_symbols.append(t + ".tick")
- self.subscribe(",".join(subscribe_symbols))
- ;获取近20日的最高价及最低价
- def get_highest_lowest_price(self, symbol):
- #print(symbol)
- ## get last N dailybars
- hd = self.get_last_n_dailybars(symbol, self.period)
- high_prices = [b.high for b in hd]
- #high_prices.reverse()
- low_prices = [b.low for b in hd]
- #low_prices.reverse()
- return np.max(high_prices), np.min(low_prices)
- def on_tick(self, tick):
- if not tick.sec_id in self.sec_ids:
- pass
- #self.logger.info( "received tick: %s %s %s %s" % (tick.exchange, tick.sec_id, round(tick.last_price,2), tick.last_volume))
- else:
- #self.logger.info( "received tick: %s %s, A: %s B: %s" % (tick.sec_id, round(tick.last_price,2), round(tick.asks[0][0],2), round(tick.bids[0][0],2)))
- symbol = ".".join([tick.exchange, tick.sec_id])
- data = self.hist_data.get(symbol)
- self.hop = float(self.hop)
- #print (data)
- pa = self.get_positions()
- #int pa
- ;开仓及平仓
- if data and tick.last_price > data[0] : ## check high
- volume = int(data[2]/(tick.last_price+self.hop)/100)*100 ## get slots, then shares
- if bool(self.get_position(tick.exchange,tick.sec_id,1)) == 0:
- #print (to_dict(aaa[0]))
- self.open_long(tick.exchange, tick.sec_id, tick.last_price + self.hop, volume)
- #print (tick.exchange, tick.sec_id, tick.last_price + self.hop, volume)
- #print (tick.sec_id)
- elif data and tick.last_price < data[1]: ## check low
- #p = self.get_position(tick.exchange, tick.sec_id, OrderSide_Bid)
- ps = self.get_positions()
- for p in ps:
- sym = ".".join([p.exchange, p.sec_id])
- self.positions[sym] = p
- #print (p)
- ## if not in stock list, close long position
- if p.sec_id in self.sec_ids:
- self.close_long(p.exchange, p.sec_id, 0, p.volume)
- if __name__ == '__main__':
- ini_file = sys.argv[1] if len(sys.argv) > 1 else 'turtle.ini'
- logging.config.fileConfig(ini_file)
- st = TurtleStrategy(config_file=ini_file)
- st.logger.info("Strategy turtle ready, waiting for data ...")
- ret = st.run()
- st.logger.info("Strategy turtle message %s" % st.get_strerror(ret))
exchange | sec_id | buy_amount(楼) | |
SZSE | 300275 | 200000 | |
SZSE | 300001 | 200000 | |
SHSE | 600000 | 200000 | |
SHSE | 600123 | 200000 | |
SHSE | 601988 | 200000 |
3. Python相关函数
3.1 Python标准函数:
功能 | 函数原型 | 参数 | 返回值 | ||
参数名 | 含义 | ||||
read_csv | 读取csv文件 | read_csv(s) | s | 文件的路径 | csv文件 |
iterrows | 行遍历 | ||||
format | 它通过{}和:来代替传统%方式 | ||||
append | 用于在列表末尾添加新的对象。 | list.append(obj) | obj | 添加到列表末尾的对象。 | 该方法无返回值,但是会修改原来的列表。 |
join | 连接字符串数组。将字符串、元组、列表中的元素以指定的字符(分隔符)连接生成一个新的字符串 | 'sep'.join(seq) | sep | 分隔符。可以为空 | 返回一个以分隔符sep连接各个元素后生成的字符串 |
seq | 要连接的元素序列、字符串、元组、字典 | ||||
max | max() 方法返回给定参数的最大值,参数可以为序列。 | max( x, y, z, .... ) | x | 数值表达式 | 返回给定参数的最大值 |
y | 数值表达式 | ||||
z | 数值表达式 | ||||
min | min() 方法返回给定参数的最大值,参数可以为序列。 | min( x, y, z, .... ) | x | 数值表达式 | 返回给定参数的最小值 |
y | 数值表达式 | ||||
z | 数值表达式 |
3.2 掘金接口函数:
功能 | 函数原型 | 参数 | 返回值 | |||
参数名 | 类型 | 说明 | ||||
subscribe | 订阅行情,策略类和行情服务了都提供该接口。 | subscribe(symbol_list) | symbol_list | string | 订阅代码列表 | |
get_last_n_dailybars | 提取单个代码的最新n条DailyBar数据, 策略类和行情服务类都提供该接口。 | get_last_n_dailybars(symbol, n, end_time='') | symbol | string | 证券代码, 带交易所代码以确保唯一,如SHSE.600000 | bar列表 |
n | int | 提取的数据条数 | ||||
end_time | string | 指定截止时间, 如2015-10-30 15:00:00 | ||||
on_tick | 响应Tick事件,收到Tick数据后本函数被调用。 | on_tick(tick) | tick | tick | tick数据 | 无 |
tick.last_price | 最新价 | |||||
get_positions | 查询当前策略指定symbol(由交易所代码和证券ID组成)和买卖方向的持仓信息。策略类和交易服务类都提供该接口。 | get_position(exchange, sec_id, side); | exchange | string | 交易所代码 | Position对象,持仓信息 |
sec_id | string | 证券代码 | ||||
side | int | 买卖方向 | ||||
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_short | 异步平空仓接口,以参数指定exchange, 证券代码sec_id, 价和量下单。如果价格为0,为市价单,否则为限价单。策略类和交易服务类都提供该接口。 | close_short(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 | 平仓量 | ||||
open_short | 异步开空仓接口,以参数指定的exchange, 证券代码sec_id, 价和量下单。如果价格为0,为市价单,否则为限价单。策略类和交易服务类都提供该接口。 | open_short(exchange, sec_id, price, volume) | exchange | string | 交易所代码, 如上交所SHSE | 委托下单生成的Order对象 |
sec_id | string | 证券代码,如浦发银行600000 | ||||
price | float | 委托价,如果price=0,为市价单,否则为限价单 | ||||
volume | float | 平仓量 |
4. 金融术语
海龟交易系统作为一个著名的交易系统,具备三个特征:第一,是一个完整的交易系统,覆盖 了交易的每个环节;第二,是一个机械化的交易系统,不给交易者留下任何主观想象决策的空间和 余地;第三,是一个已经被验证可以盈利的交易系统,在多个期货品种中都可以获得稳定性的收益。
海龟交易系统涵盖了成功交易中的每一个必要环节:买卖市场(买卖什么);头寸规模(买卖 多少);入市(何时买卖);止损(什么时候放弃一个亏损的头寸);退出(什么时候退出一个赢利 的头寸);战术(怎么进行买卖)。