均值回归策略|量化交易源码-无限易期货通

最近在尝试均值回归策略,使用无限易,感觉挺好用的。策略是面向苯乙烯,每次交易只有一手,和大家分享一下量化代码,策略还有很多不足,欢迎交流指正。

代码分解主要包括tick属性与on_order属性、其余部分大同小异,没有什么特别的地方。

在开始正式分解代码之前,介绍一下代码中会使用到的超参数与状态参数。

class Params(BaseParams):
    """参数映射模型"""
    exchange: str = Field(default="DCE", title="交易所代码")
    instrument_id: str = Field(default="eb2408", title="合约代码")
    order_volume: int = Field(default=1, title="下手单量")
    stop: int | float = Field(default=20, title="止损")
    holdstate: str = Field(default="wait", title="初始化当前状态")
class State(BaseState):
    """状态映射模型"""
    order_id: int | None = Field(default=None, title="报单编号")
    close: int | float = Field(default=0 , title="最近价")
    volume: int | float = Field(default=0, title="成交量")
    holdstate: str = Field(default="wait", title="当前状态")
    target_price: int | float = Field(default=465 , title="当前状态价")
    high_price: int | float = Field(default=0, title="当前最高价")
    low_price: int | float = Field(default=0, title="当前最低价")
    status: str = Field(default="状态正常", title="订单交易状态")
    ar10000:int | float = Field(default=0, title="ar10000")
    var10000: int | float = Field(default=0, title="var10000")

 

首先是on_order,当我们进行一次开平仓后会调用这个函数,但下单可能会面临延迟问题,或者报单失败问题。所以我再这里设置了success与finish两个状态变量,如果报单处理流程结束则finish赋值为1(方便判断是否收到了报单结果,因为这个过程会有延迟。)如果下单成功则success转换为1(若报单不成功则根据情况重新下单或保持等待)。

    def on_order(self, order: OrderData) -> None:
        super().on_order(order)
        self.output("报单信息:", order)
        if order.traded_volume>0:
            self.success=1
        if order.status=='全部成交':
            self.finish=1
接下来是主体on_tick部分
    def on_tick(self, tick: TickData) -> None:
        """收到行情 tick 推送"""

        super().on_tick(tick)
        # 过滤涨跌停和集合竞价
        # self.output(tick.last_price,tick.last_volume,tick.datetime)
        if tick.last_price == 0 or tick.ask_price1 == 0 or tick.bid_price1 == 0 :
            return
        # self.output(self.state_map.holdstate)
        self.update_status_bar()

        self.close.append(tick.last_price)
        self.close = self.close[1:]
        self.ar10000 = self.close[-10000:]
        self.state_map.ar10000 = np.mean(self.ar10000)
        self.state_map.var10000 = np.std(self.ar10000)

on_tick回调一开始会过滤集合竞价与涨跌停,但实操下来发现,这套官方的方法并不能很好的过滤集合竞价。在on_tick的开始阶段不断收级最近的成交价,保存到self.close中,并且不断计算过去10000此成交价的均值与标准差。为完成回归策略做准备。

self.state_map.high_price=self.state_map.ar10000+40#3*self.state_map.var10000
self.state_map.low_price = self.state_map.ar10000-40

上面定义了压力位和支撑位,这里定义的是高于或低于均线40个点即进入压力位或支撑位,当然也可以像注释中一样使用标准差进行定义。

self.signal1 = tick.last_price <= self.state_map.low_price
self.signal1_1 = tick.last_price > self.state_map.low_price+2 and tick.ask_price1 - tick.bid_price1 < 4
self.signal2 = tick.last_price >= self.state_map.high_price
self.signal2_1 = tick.last_price < self.state_map.high_price-2 and tick.ask_price1 - tick.bid_price1 < 4

上为两阶段交易信号,以做多为例,当价格低于low_price,则满足第一阶段,当价格再次高于low_price则完成一次做多信号。在信号中使用价差进行了滑点处理,减少止损止盈误差。

        if self.state_map.holdstate=='station':
            # self.output(self.finish,self.success)
            if self.finish:
                if self.success:
                    self.state_map.holdstate = self.next_state
                    self.success=0
                else:
                    self.state_map.holdstate = self.current_state
                self.finish=0
            else:
                self.state_map.holdstate='station'

策略使用状态来描述当前状况,station状态是一个下单后的“中转站”,如果下单后的结果未返回则保持在station等待(self.finish来实现),如果下单未成功则返回下单前的一个状态,反之则进入下单后的状态(self.success来实现)。下面以做多为例分解代码,做空与做多完全对称。

        elif self.state_map.holdstate == 'wait':
            if self.signal1:
                self.state_map.holdstate = 'poswait'
            elif self.signal2:
                self.state_map.holdstate = 'negwait'

等待状态,判断当前的成交价是否满足第一阶段。若此时满足signal1则进入poswait状态。

        elif self.state_map.holdstate=='poswait':
            if self.signal1_1:
                self.state_map.order_id = self.send_order(
                    exchange=self.params_map.exchange,
                    instrument_id=self.params_map.instrument_id,
                    volume=self.params_map.order_volume,
                    price=tick.ask_price1,
                    order_direction="buy"
                )
                self.state_map.target_price = tick.ask_price1
                self.current_state='poswait'
                self.next_state='poshold'
                self.state_map.holdstate = 'station'

进入poswait状态后若价格再次回到支撑位以上,则开多单,并进入station状态判断是否下单成功,若成功则进入poshold状态。

elif self.state_map.holdstate == 'poshold':
    if tick.last_price>=self.state_map.ar10000:
        self.state_map.order_id =
                       self.auto_close_position(exchange=self.params_map.exchange,                                                                          
                       instrument_id=self.params_map.instrument_id,                                                                 
                       volume=self.params_map.order_volume,
                       price=tick.bid_price1,
                       order_direction="sell" )
        self.current_state = 'poshold'
        self.next_state = 'wait'
        self.state_map.holdstate = 'station'
    elif tick.last_price<=self.state_map.target_price-self.params_map.stop:
        self.state_map.order_id = 
                       self.auto_close_position(exchange=self.params_map.exchange,                                                                
                       instrument_id=self.params_map.instrument_id,                                                                  
                       volume=self.params_map.order_volume,
                       price=tick.bid_price1,
                       order_direction="sell")
        self.current_state = 'poshold'
        self.next_state = 'wait+'
        self.state_map.holdstate = 'station'

在多单持有状态中,若成交价成功回到均线,则进行止盈,并且状态回到’wait‘。此外,若成交价不仅没有回到均线,反而跌破了止损价,则进入一个“wait+”状态,当前的突破有可能发生了大的行情趋势,“wait+”状态的功能在于当价格回归到一个相对稳定的区间后才再次进行交易,否则进入一个等待状态。

        elif self.state_map.holdstate == 'wait+':
            if tick.last_price>self.state_map.low_price:
                self.state_map.holdstate='wait'

 

最后,附一下完整代码
from typing import Literal
import pandas as pd
import numpy as np
import csv
from pythongo.base import BaseParams, BaseState, BaseStrategy, Field
from pythongo.classdef import OrderData,TickData
# from pythongo.classdef import KLineData, TickData

class Params(BaseParams):
    """参数映射模型"""
    exchange: str = Field(default="DCE", title="交易所代码")
    instrument_id: str = Field(default="eb2408", title="合约代码")
    order_volume: int = Field(default=1, title="下手单量")
    stop: int | float = Field(default=20, title="止损价格")
    holdstate: str = Field(default="wait", title="初始化当前状态")
    target_price: int | float = Field(default=9698, title="初始化当前状态价")




class State(BaseState):
    """状态映射模型"""
    order_id: int | None = Field(default=None, title="报单编号")
    close: int | float = Field(default=0 , title="最近价")
    volume: int | float = Field(default=0, title="成交量")
    holdstate: str = Field(default="wait", title="当前状态")
    target_price: int | float = Field(default=465 , title="当前状态价")
    high_price: int | float = Field(default=0, title="当前最高价")
    low_price: int | float = Field(default=0, title="当前最低价")
    status: str = Field(default="状态正常", title="订单交易状态")
    ar10000:int | float = Field(default=0, title="ar10000")
    var10000: int | float = Field(default=0, title="var10000")
    stop: int | float = Field(default=20, title="止损")


class VARIANCE(BaseStrategy):
    def __init__(self) -> None:
        super().__init__()
        self.params_map = Params()
        self.state_map = State()
        df = pd.read_csv('C:/Users/lantian/Desktop/tick数据/eb2408.csv').iloc[-10100:, :]
        self.close = list(df['last_price'])
        self.ar10000 = self.close[-10000:]
        self.success = 0
        self.finish=0
        # self.open=1
        # self.askcut = np.mean(self.askar)-np.mean(self.bidar)

    def on_order(self, order: OrderData) -> None:
        super().on_order(order)
        self.output("报单信息:", order)
        if order.traded_volume>0:
            self.success=1
        if order.status=='全部成交':


            self.finish=1

    def on_start(self) -> None:
        super().on_start()
        self.state_map.holdstate = self.params_map.holdstate
        self.state_map.target_price = self.close[-1]
        self.state_map.high_price = np.mean(self.ar10000)+3*np.std(self.ar10000)
        self.state_map.low_price = np.mean(self.ar10000)-3*np.std(self.ar10000)
        self.update_status_bar()
        self.state_map.ar10000 = np.mean(self.ar10000)
        self.state_map.var10000 = np.std(self.ar10000)

    def on_tick(self, tick: TickData) -> None:
        """收到行情 tick 推送"""

        super().on_tick(tick)
        # 过滤涨跌停和集合竞价
        # self.output(tick.last_price,tick.last_volume,tick.datetime)
        if tick.last_price == 0 or tick.ask_price1 == 0 or tick.bid_price1 == 0 :
            return
        # self.output(self.state_map.holdstate)
        self.update_status_bar()

        self.close.append(tick.last_price)
        self.close = self.close[1:]
        self.ar10000 = self.close[-10000:]
        self.state_map.ar10000 = np.mean(self.ar10000)
        self.state_map.var10000 = np.std(self.ar10000)

        self.state_map.high_price=self.state_map.ar10000+40#3*self.state_map.var10000
        self.state_map.low_price = self.state_map.ar10000-40#3*self.state_map.var10000
        self.state_map.close = tick.last_price
        self.signal1 = tick.last_price <= self.state_map.low_price
        self.signal1_1 = tick.last_price > self.state_map.low_price+2 and tick.ask_price1 - tick.bid_price1 < 4
        self.signal2 = tick.last_price >= self.state_map.high_price
        self.signal2_1 = tick.last_price < self.state_map.high_price-2 and tick.ask_price1 - tick.bid_price1 < 4
        if self.state_map.holdstate=='station':
            # self.output(self.finish,self.success)
            if self.finish:
                if self.success:
                    self.state_map.holdstate = self.next_state
                    self.success=0
                else:
                    self.state_map.holdstate = self.current_state
                self.finish=0
            else:
                self.state_map.holdstate='station'

        elif self.state_map.holdstate == 'wait':
            if self.signal1:
                self.state_map.holdstate = 'poswait'
            elif self.signal2:
                self.state_map.holdstate = 'negwait'
            #初始做多

        elif self.state_map.holdstate=='poswait':
            if self.signal1_1:
                self.state_map.order_id = self.send_order(
                    exchange=self.params_map.exchange,
                    instrument_id=self.params_map.instrument_id,
                    volume=self.params_map.order_volume,
                    price=tick.ask_price1,
                    order_direction="buy"
                )
                self.state_map.target_price = tick.ask_price1
                self.current_state='poswait'
                self.next_state='poshold'
                self.state_map.holdstate = 'station'
                    # self.success=0
        elif self.state_map.holdstate == 'negwait':
            if self.signal2_1 :
                self.state_map.order_id = self.send_order(
                    exchange=self.params_map.exchange,
                    instrument_id=self.params_map.instrument_id,
                    volume=self.params_map.order_volume,
                    price=tick.bid_price1,
                    order_direction="sell"
                )
                self.state_map.target_price  = tick.bid_price1
                self.current_state = 'negwait'
                self.next_state = 'neghold'
                self.state_map.holdstate = 'station'

        elif self.state_map.holdstate == 'poshold':
            if tick.last_price>=self.state_map.ar10000:
                self.state_map.order_id = self.auto_close_position(exchange=self.params_map.exchange,
                                                                   instrument_id=self.params_map.instrument_id,
                                                                   volume=self.params_map.order_volume,
                                                                   price=tick.bid_price1,
                                                                   order_direction="sell"
                                                                   )
                self.current_state = 'poshold'
                self.next_state = 'wait'
                self.state_map.holdstate = 'station'

            elif tick.last_price<=self.state_map.target_price-self.params_map.stop:
                self.state_map.order_id = self.auto_close_position(exchange=self.params_map.exchange,
                                                                   instrument_id=self.params_map.instrument_id,
                                                                   volume=self.params_map.order_volume,
                                                                   price=tick.bid_price1,
                                                                   order_direction="sell"
                                                                   )
                self.current_state = 'poshold'
                self.next_state = 'wait+'
                self.state_map.holdstate = 'station'


        elif self.state_map.holdstate == 'neghold':
            if tick.last_price<=self.state_map.ar10000:
                self.state_map.order_id = self.auto_close_position(exchange=self.params_map.exchange,
                                                                   instrument_id=self.params_map.instrument_id,
                                                                   volume=self.params_map.order_volume,
                                                                   price=tick.ask_price1,
                                                                   order_direction="buy"
                                                                   )
                self.current_state = 'neghold'
                self.next_state = 'wait'
                self.state_map.holdstate = 'station'
            elif tick.last_price >= self.state_map.target_price + self.params_map.stop:
                self.state_map.order_id = self.auto_close_position(exchange=self.params_map.exchange,
                                                                   instrument_id=self.params_map.instrument_id,
                                                                   volume=self.params_map.order_volume,
                                                                   price=tick.ask_price1,
                                                                   order_direction="buy"
                                                                   )
                self.current_state = 'neghold'
                self.next_state = 'wait-'
                self.state_map.holdstate = 'station'
        elif self.state_map.holdstate == 'wait+':
            if tick.last_price>self.state_map.low_price:
                self.state_map.holdstate='wait'
        elif self.state_map.holdstate == 'wait-':
            if tick.last_price<self.state_map.high_price:
                self.state_map.holdstate='wait'

    def on_stop(self) -> None:
        super().on_stop()
        self.output("我的第一个策略暂停了")

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值