掘金社区

分享一个python均线策略Pinned highlighted

逍遥游 发表在掘金2 2015-08-22 09:03:09

掘金2
13153
16
0

简单的基于ta-lib的均线策略示例

策略简介,主要是基于分时线的close线跟MA之间的关系出信号,同时对信号有个简单的过滤逻辑,同时展示了怎么调用gmsdk来做仓位管理。订单管理并没有在代码中体现, 如果需要对委托订单的状态进行跟踪,还需要增加on_order_status函数,用来跟踪订单的执行状态。

策略逻辑: 用分时bar线的收盘价跟ma线之间的交叉关系发出信号,并根据配置做一个简单的信号过滤。 用一个数列配置下单量,在出信号后,根据已有持仓状态确定是否开仓,或者是继续加仓,或者是回调加仓,还是加仓次数达上限后主动平仓出场。

在代码中添加了一些注释,希望有助于阅读。

注: 代码仅为示例,各参数设置和逻辑都不够严谨,切勿直接用于实盘交易。

#!/usr/bin/env python
# encoding: utf-8


import time
from talib.abstract import SMA
import numpy as np
from collections import deque
from gmsdk import *

# 算法用到的一些常量,阀值,主要用于信号过滤
eps = 1e-6
threshold = 0.235
tick_size = 0.2
half_tick_size = tick_size / 2
significant_diff = tick_size * 2.6

class MA(StrategyBase):

    """ strategy example1: MA decision price cross long MA, then place a order, temporary reverse trends place more orders """

    def __init__(self, *args, **kwargs):
        #import pdb; pdb.set_trace()
        super(MA, self).__init__(*args, **kwargs)
        # 策略初始化工作在这里写,从外部读取静态数据,读取策略配置参数等工作,只在策略启动初始化时执行一次。

        # 从配置文件中读取配置参数
        self.exchange = self.config.get("para", "trade_exchange")
        self.sec_id = self.config.get("para", "trade_symbol")
        self.symbol = ".".join([self.exchange, self.sec_id])
        self.last_price = 0.0
        self.trade_unit = [1.0, 2.0, 4.0, 8.0, 5.0, 3.0,2.0,1.0,1.0, 0.0] ##  [8.0, 4.0, 2.0, 1.0]
        self.trade_count = 0
        self.trade_limit = len(self.trade_unit)
        self.window_size = self.config.getint("para", "window_size") or 60
        self.timeperiod = self.config.getint("para", "timeperiod")
        self.bar_type = self.config.getint("para", "bar_type") 
        self.close_buffer = deque(maxlen=self.window_size)
        self.significant_diff = self.config.getfloat("para", "significant_diff") or significant_diff

        # prepare historical bars for MA calculating
        # 从数据服务中准备一段历史数据,使得收到第一个bar后就可以按需要计算ma
        last_closes = [bar.close for bar in self.get_last_n_bars(self.symbol, self.bar_type, self.window_size)]
        last_closes.reverse()     #因为查询出来的时间是倒序排列,需要倒一下顺序
        self.close_buffer.extend(last_closes)

    # 响应bar数据到达事件
    def on_bar(self, bar):
        # 确认下bar数据是订阅的分时
        if bar.bar_type == self.bar_type:
            # 把数据加入缓存
            self.close_buffer.append(bar.close)
            # 调用策略计算
            self.algo_action()

   # 响应tick数据到达事件
    def on_tick(self, tick):
        # 更新市场最新成交价
        self.last_price = tick.last_price

    def on_execution(self, execution):
        #打印订单成交回报信息
        print "received execution: %s" % execution.exec_type

    #策略的算法函数,策略的交易逻辑实现部分
    def algo_action(self):
        #数据转换,方便调用ta-lib函数进行技术指标的计算,这里用SMA指标
        close = np.asarray(self.close_buffer)
        ma = SMA({"close":close}, timeperiod=self.timeperiod)
        delta = round(close[-1] - ma[-1],4)     # 最新数据点,bar的收盘价跟ma的差
        last_ma = round(ma[-1], 4)  #  均线ma的最新值
        momentum = round(self.last_price - last_ma,4)  # 当前最新价格跟ma之间的差,成交价相对ma偏离
        #print "close: ", close
        print("close ma delta: {0}, last_ma: {1}, momentum: {2}".format(delta, last_ma, momentum))

        a_p = self.get_position(self.exchange, self.sec_id, OrderSide_Ask)    #查询策略所持有的空仓
        b_p = self.get_position(self.exchange, self.sec_id, OrderSide_Bid)    #查询策略所持有的多仓
        # 打印持仓信息
        print ("pos long: {0} vwap: {1}, pos short: {2}, vwap: {3}".format(b_p.volume if b_p else 0.0,
                round(b_p.vwap,2) if b_p else 0.0,
                a_p.volume if a_p else 0.0,
                round(a_p.vwap,2) if a_p else 0.0))
        if delta > threshold and momentum >= significant_diff:        ## 收盘价上穿均线,且当前价格偏离满足门限过滤条件,多信号
            # 没有空仓,且没有超出下单次数限制
            if (a_p is None or a_p.volume < eps) and self.trade_count < self.trade_limit:
                # 依次获取下单的交易量,下单量是配置的一个整数数列,用于仓位管理,可用配置文件中设置
                vol = self.trade_unit[self.trade_count]
                # 如果本次下单量大于0,  发出买入委托交易指令
                if vol > eps:
                    self.open_long(self.exchange, self.sec_id, self.last_price, vol)
                self.trade_count += 1    #增加计数
            else:
                #  如果有空仓,且达到本次信号的交易次数上限
                if a_p and a_p.volume > eps and self.trade_count == self.trade_limit:
                    self.close_short(self.exchange, self.sec_id, self.last_price, a_p.volume)    # 平掉所有空仓
                    self.trade_count = 0
                else:
                    # 有空仓时,且上次交易信号后没达到交易次数限制,继续加空
                    vol = self.trade_unit[self.trade_count] if self.trade_count < self.trade_limit else 0.0
                    self.trade_count += 1
                    if vol > eps:
                        self.open_short(self.exchange, self.sec_id,self.last_price, vol)
        elif delta < -threshold and momentum <= - significant_diff:     ## bar 收盘价下穿ma均线,且偏离满足信号过滤条件
            # 没有多仓时,开空
            if (b_p is None or b_p.volume < eps) and self.trade_count < self.trade_limit:
                vol = self.trade_unit[self.trade_count]
                self.trade_count += 1
                if vol > eps:
                    self.open_short(self.exchange, self.sec_id, self.last_price, vol)
            else:
                # 已有多仓,且达到了交易次数限制,平掉多仓
                if b_p and b_p.volume > eps and self.trade_count == self.trade_limit:
                    self.close_long(self.exchange, self.sec_id, self.last_price, b_p.volume)
                    self.trade_count = 0
                else:
                    # 已有多仓,且没有达到交易次数限制,继续加多
                    vol = self.trade_unit[self.trade_count] if self.trade_count < self.trade_limit else 0.0
                    self.trade_count += 1
                    if vol > eps:
                        self.open_long(self.exchange, self.sec_id, self.last_price, vol)
        else:       ##  其他情况,忽略不处理
            ## get positions and close if any
            #self.trade_count = 0   ## reset trade count
            pass

# 策略启动入口
if __name__ == "__main__":
    #  初始化策略
    ma = MA(config_file="strategy_ma.ini")
    #import pdb; pdb.set_trace()   # python调试开关
    print "strategy ready, waiting for market data ......"
    # 策略进入运行,等待数据事件
    ret = ma.run()
    # 打印策略退出状态
    print "MA :", ma.get_strerror(ret)

以下是它用的配置文件示例

[strategy]
;md_addr=120.24.228.187:8000
td_addr=localhost:8001
username=demo@myquant.cn
password=123456
mode=2
strategy_id=stategy_4
subscribe_symbols=SHFE.ag1512.tick,SHFE.ag1512.bar.60
;start_time=2014-05-26 09:00:00
;end_time=2014-05-26 16:00:00

[para]
trade_exchange=SHFE
trade_symbol=ag1512
window_size=20
bar_type=15
tick_size=1
significant_diff=21
timeperiod=20


##############################################################
# logger settings
##############################################################
[loggers]
keys=root

[logger_root]
level=DEBUG
handlers=console,file

[handlers]
keys=console,file

[handler_file]
class=handlers.RotatingFileHandler
args=("strategy_dual_ma.log","a","maxBytes=10000","backupCount=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=
评论: 16
  • 我想问一下这个策略是从哪里找到的啊?
    我想要开发一些基于各种常见技术指标的策略,感谢管理员的这个例子,不知道有没有其他的例子了。此致

    2015-09-15 06:54:36
  • 我们提供的示例策略,其他指标,比如RSI, MACD等可以参考这个例子,ta-lib中180多个常用指标都可以使用的。

    2015-09-16 06:20:10
  • 这个写的我都晕了,均线策略怎么写的这么复杂。要是方便,还是请您分享一下策略的思路,各参数含义,以及给代码加上注释,

    2015-10-18 14:22:19
  • 这个是个演示策略,主要是基于分时线的close线跟MA之间的关系出信号,同时对信号有个简单的过滤逻辑,同时展示了怎么调用gmsdk来做仓位管理。订单管理并没有在代码中体现, 如果需要对委托订单的状态进行跟踪,还需要增加on_order_status函数,用来跟踪订单的执行状态。

    在代码中加了些注释,希望有助于理解。

    2015-10-25 09:30:23
  • 谢谢您,我也大致看懂了。只是咱们这边忒冷清了,没啥策略实例,相比其他平台,上手难度大一些。

    2015-11-03 16:53:31
  • 我们正在逐步增加一些策略示例,并增加一些基本类型的策略模板,如果有朋友愿意共享一些这方面的素材,我们将非常感谢!

    为了方便策略代码的分享和展示,以及BUG的管理,我们决定在github上用开源项目的方式把一些经典策略在掘金量化平台上的实现管理起来,方便大家学习和分享。

    我们已经在github上建立了一个开源项目 myquant/strategy https://github.com/myquant/strategy ,其中会逐步增加一些经典的策略示例实现,主要包括策略思路,各语言的代码实现,这个策略的python代码已经放上去,如果有朋友有兴趣,可以直接fork这个策略的代码,自己再做修改,如果愿意贡献一些经典的策略代码实现,请在github中操作修改。

    github项目介绍文件如下:

    掘金策略集锦

    量化开源和分享,展示各类经典策略在掘金平台下的实现。

    每个策略单独拥有一个目录,目录名即是该策略的简称,里面有一个固定名为info.md的文件,其内容为该策略的简单介绍。
    策略的每种实现为单独一个目录,目录名为该策略的实现语言,因为一些语言下的代码实现可能有一系列文件,所以把每一种策略实现语言单列为一个目录,
    比如,一个策略有python实现,就有一个python目录,里面是python代码文件,如果还有C#实现,就会有一个csharp目录。

    目录结构组织如下:

    -- strategy  策略名
    
    |—— info.md  策略介绍
    
    |—— python   策略python实现
    
       |— strategy.py  策略代码
       
       |- strategy.ini 策略的配置文件
    
    |—— csharp   策略csharp实现
    
       |— strategy.cs  策略代码
    
       |- strategy.ini 策略的配置文件
    

    策略列表,逐步增加中,有需求或计划共享自己实现的一些经典策略的,请fork本项目,然后修改这个文件,并做Pull Request。

    1. 双均线策略 dual-ma
    2. 区间突破策略 dual-thrust
    3. 动态突破策略 Dynamic Breakout

    ......

    2015-11-19 10:40:28
  • 这是python2.7? 不是只支持3.5么。。

    2016-03-24 12:29:24
  • rbreaker的没写全吧。。完全没用。。都不修改任何pre_high..

    2016-03-25 02:50:58
  • python2.7, python3.5都支持。最新的策略示例见github: https://github.com/myquant/strategy

    2016-03-25 07:21:51
  • 下下来了,但似乎都不太全..也不能回测。。改hans123中,看起来修改简单一些。rbreaker不好改。

    2016-03-25 12:59:38
  • 给你这个策略找bug比自己写一个策略还要难。。。

    2016-04-02 12:59:13
  • 这不是我的策略是git上的样本。。

    2016-04-07 02:24:20
  • 跨日的话要从新调用__init_data()函数,还有timestamp也要更新。

    2016-04-07 06:06:46
  • 谢谢,楼主分享。python好学么?我只在BotVS上用javascript写过策略,python的还不是很熟悉,只看懂一点点。

    2016-05-07 01:19:59
  • @summer python较全教程http://www.runoob.com/python/python-intro.html

    2018-04-04 09:54:34
  • class MA(StrategyBase): StrategyBase is not defined.

    2019-08-17 20:41:18

Looks like your connection to 掘金量化社区 - 量化交易者的策略交流学习社区 was lost, please wait while we try to reconnect.