资源加载中... loading...

生猪基差回归套利策略

Author: ianzeng123, Date: 2024-04-24 11:34:09
Tags:


import json

class TradingStrategy:
    def __init__(self, pigPeriod, pigWidth):
        self.cfgA = {
            "extension": {
                "layout": 'single',
                "col": 6,
                "height": "500px",
            },
            "title": {
                "text": "期现图表"
            },
            "xAxis": {
                "type": "datetime"
            },
            "series": [{
                "name": "期货价格",
                "data":  [17300.0, 17695.0, 17590.0, 17780.0, 17780.0, 18070.0, 17990.0, 18175.0, 18200.0, 18055.0, 18100.0, 18255.0, 18250.0, 18110.0, 18300.0, 18470.0, 18155.0, 18225.0, 18305.0, 18225.0, 17930.0, 17980.0, 17890.0, 17965.0, 18280.0, 18305.0, 18185.0, 18155.0, 18210.0, 17960.0, 18140.0, 18385.0, 18210.0, 17900.0, 17880.0, 17880.0, 17625.0, 17580.0, 17630.0, 17540.0, 17475.0, 17300.0, 17495.0, 17285.0, 17580.0, 17630.0, 17620.0, 17560.0, 17660.0, 17795.0, 17860.0, 17855.0, 17845.0, 17980.0, 17930.0, 18010.0, 17580.0, 17900.0],
            }, {
                "name": "现货价格",
                "data":  [14880, 14870, 14870, 14880, 14880, 14880, 14930, 14970, 15050, 15150, 15230, 15230, 15450, 15570, 15670, 15900, 16230, 16230, 16600, 16900, 16900, 17430, 17420, 17420, 17600, 17800, 18000, 18020, 18100, 18100, 18350, 18530, 18600, 18600, 18600, 18600, 18570, 18520, 18380, 18330, 18330, 18030, 17720, 17630, 17630, 17630, 17630, 17900, 17880, 17950, 18050, 18270, 18270, 18320, 18430, 18500, 18500, 18500],
            }]
        }
        self.cfgB = {
            "extension": {
                "layout": 'single',
                "col": 6,
                "height": "500px",
            },
            "title": {
                "text": "基差图表"
            },
            "xAxis": {
                "type": "datetime"
            },
            "series": [{
                "name": "基差价格",
                "data": [-2420.0, -2825.0, -2720.0, -2900.0, -2900.0, -3190.0, -3060.0, -3205.0, -3150.0, -2905.0, -2870.0, -3025.0, -2800.0, -2540.0, -2630.0, -2570.0, -1925.0, -1995.0, -1705.0, -1325.0, -1030.0, -550.0, -470.0, -545.0, -680.0, -505.0, -185.0, -135.0, -110.0, 140.0, 210.0, 145.0, 390.0, 700.0, 720.0, 720.0, 945.0, 940.0, 750.0, 790.0, 855.0, 730.0, 225.0, 345.0, 50.0, 0.0, 10.0, 340.0, 220.0, 155.0, 190.0, 415.0, 425.0, 340.0, 500.0, 490.0, 920.0, 600.0],
            }]
        }
        self.chart = Chart([self.cfgA, self.cfgB])  # 创建一个图表对象

        # 初始化其他全局变量
        self.info = []
        self.basis = 0
        self.spot = 0
        self.basisList = [-2420.0, -2825.0, -2720.0, -2900.0, -2900.0, -3190.0, -3060.0, -3205.0, -3150.0, -2905.0, -2870.0, -3025.0, -2800.0, -2540.0, -2630.0, -2570.0, -1925.0, -1995.0, -1705.0, -1325.0, -1030.0, -550.0, -470.0, -545.0, -680.0, -505.0, -185.0, -135.0, -110.0, 140.0, 210.0, 145.0, 390.0, 700.0, 720.0, 720.0, 945.0, 940.0, 750.0, 790.0, 855.0, 730.0, 225.0, 345.0, 50.0, 0.0, 10.0, 340.0, 220.0, 155.0, 190.0, 415.0, 425.0, 340.0, 500.0, 490.0, 920.0, 600.0]
        self.holdprice = '-'
        self.holddir = '-'
        self.holdprofit = 0
        self.pos = []
        self.pre_data = []

        self.pigPeriod = pigPeriod
        self.pigWidth = pigWidth

        self.initAccount = _C(exchange.GetAccount)  # 获取初始账户信息

    def update_spot_and_basis(self, futures_price):
        obj = exchange.GetData("https://www.datadata.cn/api/v1/query/94af6e1e-2efa-4e0c-8c08-f7853b2bf969/data")

        if obj["Data"] != self.pre_data:
            self.pre_data = obj["Data"]
            self.info = json.loads(obj["Data"])
            self.spot = self.info['spot_price']
            self.basis = self.spot - futures_price
            self.basisList.append(self.basis)

    def plot_data(self, futures_ts, futures_price):
        self.chart.add(0, [futures_ts, futures_price])  # 绘制期货价格
        self.chart.add(1, [futures_ts, self.spot])  # 绘制现货价格
        self.chart.add(2, [futures_ts, self.basis])  # 绘制基差
        self.chart.update([self.cfgA, self.cfgB])  # 更新图表

    def handle_position(self, futures_price, mainid):
        basisBoll = TA.BOLL(self.basisList, self.pigPeriod, self.pigWidth)
        p = ext.NewPositionManager()
        self.pos = exchange.GetPosition()

        if len(self.pos) != 0 and self.pos[0].ContractType != mainid:
            p.Cover(self.pos[0].ContractType)
            Log('今日主力合约:', mainid, '平旧仓: ', self.pos[0].ContractType, '#FFA500')
            self.basisList = []  # 重新开始计算基差

        if len(self.basisList) < self.pigPeriod + 2:
            return

        if self.basis > basisBoll[0][-2] and len(self.pos) == 0:
            Log('基差上限:', basisBoll[0][-2], '基差下限:', basisBoll[2][-2], '当今基差:', self.basis)
            Log('基差过大,期货开多仓', '#ff0000')
            p.OpenLong(mainid, 1)

        if len(self.pos) == 1 and self.pos[0].Type == 0 and (self.basis < basisBoll[1][-2]):
            Log('基差上限:', basisBoll[0][-2], '基差下限:', basisBoll[2][-2], '当今基差:', self.basis)
            Log('基差回归,期货平仓', '#0000ff')
            p.Cover(mainid)

        if self.basis < basisBoll[2][-2] and len(self.pos) == 0:
            Log('基差上限:', basisBoll[0][-2], '基差下限:', basisBoll[2][-2], '当今基差:', self.basis)
            Log('基差过小,期货开空仓', '#00ff00')
            p.OpenShort(mainid, 1)

        if len(self.pos) == 1 and self.pos[0].Type == 1 and (self.basis > basisBoll[1][-2]):
            Log('基差上限:', basisBoll[0][-2], '基差下限:', basisBoll[2][-2], '当今基差:', self.basis)
            Log('基差回归,期货平仓', '#0000ff')
            p.Cover(mainid)

    def update_status_table(self, futures_price):
        positions = _C(exchange.GetPosition)
        tblStatus = {
            "type": "table",
            "title": "策略状态",
            "cols": ["现货价格", "期货价格", "基差", "持仓均价", "持仓方向", "持仓盈亏"],
            "rows": []
        }

        if len(positions) != 0:
            self.holdprice = positions[0].Price
            self.holddir = '多头' if positions[0].Type == 0 else '空头'
            self.holdprofit = (futures_price - positions[0].Price) * 16 if positions[0].Type == 0 else (futures_price - positions[0].Price) * -16
        else:
            self.holdprice = 0
            self.holddir = '-'
            self.holdprofit = '-' 

        tblStatus["rows"].append([self.spot, futures_price, self.basis, self.holdprice, self.holddir, self.holdprofit])
        return tblStatus

    def log_profit_and_status(self, futures_price):
        cur_time = int(_D()[0:10].replace("-", ""))  # 获取当前日级别时间
        curAccount = _C(exchange.GetAccount)
        curProfit = float(curAccount.Info.Balance) - float(self.initAccount.Info.Balance)
        LogProfit(curProfit, "&")

        tblStatus = self.update_status_table(futures_price)
        lastStatus = f"`{json.dumps(tblStatus)}`\n当前时间: {cur_time}"
        LogStatus(lastStatus)

    def onTick(self):
        maininfo = _C(exchange.SetContractType, "lh888")  # 订阅期货品种
        mainid = maininfo['InstrumentID']
        futures = _C(exchange.GetRecords)[-1]  # 获取最新K线数据
        futures_ts = futures.Time  # 获取最新K线期货时间戳
        futures_price = futures.Close  # 获取最新K线收盘价

        self.update_spot_and_basis(futures_price)
        self.plot_data(futures_ts, futures_price)
        self.handle_position(futures_price, mainid)
        self.log_profit_and_status(futures_price)


def main():
    SetErrorFilter("502:|503:|tcp|character|unexpected|network|timeout|WSARecv|Connect|GetAddr|no such|reset|http|received|EOF|reused|(CTP_T@10010)|Futures_OP 3: not login")
    strategy = TradingStrategy(pigPeriod, pigWidth)
    LogReset()  # 运行前先清空之前的Log日志信息
    strategy.chart.reset()  # 运行前先清空之前的图表信息
    
    while True:  # 进入循环模式
        if exchange.IO('status'):
            strategy.onTick()  # 执行策略主函数
        Sleep(1000 * 60 * 60 * 24)  # 策略休眠一天



更多内容