avatar of ianzeng123 ianzeng123
关注 私信
2
关注
319
关注者

浅谈数字货币做市策略(2):盘口策略

创建于: 2025-08-01 11:28:35, 更新于: 2025-08-04 14:15:40
comments   0
hits   692

浅谈数字货币做市策略(2):盘口策略

前言

在上一篇文章《数字货币中的刷量型对敲策略》中,我们详细介绍了一种通过同价买卖来积累交易量的策略框架。该策略的主要目的是获取交易所返佣或等级优惠,而非通过价差套利获得收益。虽然刷量型对敲策略在学习交易框架架构方面具有参考价值,但其实际盈利能力有限,且可能面临合规风险。

本篇文章将在前文的基础上,介绍另一种更具实用价值的做市策略——盘口策略。与刷量型对敲策略不同,盘口策略是一种真正的套利策略,通过在买卖价格之间设置价差来获取收益,更符合传统做市商的盈利模式。

⚠️ 重要声明

本文展示的盘口策略代码仅为学习参考框架,不具有任何实盘运行经验。文中的策略实现仅用于技术学习和研究目的,未经过实际市场环境的充分验证。读者在参考本文内容时,务必进行充分的回测验证和风险评估,切勿直接用于实盘交易。


盘口策略原理

盘口策略是一种利用市场订单簿(即盘口深度)进行套利的做市策略。在这种策略下,做市商通过在买卖价格的差距内,根据市场波动动态调整挂单价格,进行挂单和撤单操作,从而利用市场的流动性和短期价格波动来获得利润。

核心特点

  1. 动态调整挂单价格:根据市场深度和价格波动,动态调整买卖单的价格,以提高成交概率。
  2. 控制挂单数量:根据账户资金和持仓情况,控制挂单数量,避免过度暴露在市场风险中。
  3. 订单状态管理:定期检查订单状态,处理未完成的订单。

与对敲策略的区别

特征 刷量型对敲策略 盘口策略
买卖价格 相同价格 不同价格(有价差)
盈利模式 交易所返佣/激励 买卖价差
风险暴露 低(同价成交) 高(价格波动风险)
实用性 有限 较高

盘口策略的优势

  • 提高市场流动性:通过在盘口挂单,增加市场的买卖深度,吸引更多交易者参与。
  • 赚取买卖价差:通过提供流动性,做市商可以赚取买卖价差,从而获得收益。
  • 灵活应对市场波动:盘口策略可以根据市场波动动态调整挂单价格,降低市场风险。

盘口策略的挑战

  • 市场风险:市场价格波动可能导致做市商的挂单无法成交,甚至造成亏损。
  • 资金压力:做市商需要足够的资金来维持盘口的买卖深度,资金不足可能导致策略失效。
  • 订单管理复杂:盘口策略需要定期检查订单状态,处理未完成的订单,增加了策略的复杂性。

盘口策略结构

与对敲策略一致,本文的代码实现了一个基于盘口策略的做市策略,主要分为两个类:

  1. MidClass:交易所中间层,负责与交易所的接口交互,获取市场数据、账户信息、订单状态等。
  2. MarketMaker:做市策略类,负责执行盘口策略,动态生成挂单价格,生成挂单、检查订单状态、更新策略状态等。

盘口策略流程

1. 初始化

MarketMaker 类的初始化方法中,首先获取交易所的精度信息,并初始化策略参数,如交易量精度、价格精度等。

self.precision_info = self.exchange_mid.get_precision()  # 获取精度信息
self.price_precision = self.precision_info['price_precision']  # 价格精度
self.amount_precision = self.precision_info['amount_precision']  # 交易量精度

2. 生成盘口挂单字典

盘口策略的核心是生成盘口挂单字典,包含买卖价格和数量。代码中通过计算中间价和价格偏移量,生成盘口挂单字典。

3. 盘口挂单价格的移动

盘口挂单价格的移动是通过计算价格偏移量来实现的。价格偏移量是根据价格范围(price_range)和最小价格间隔(min_price_step)计算得出的。

price_offset = price_range - self.pending_order_count * min_price_step  # 计算价格偏移量
do_trade = price_offset > 0
  • price_range:价格范围,表示挂单价格与中间价的偏离范围。
  • min_price_step:最小价格间隔,表示每次挂单价格的最小调整步长。
  • price_offset:价格偏移量,表示当前挂单价格与中间价的偏离量。

如果价格偏移量大于 0,则表示可以继续挂单;否则,重置挂单次数。

4. 生成挂单字典

根据价格偏移量,计算买卖价格,并生成挂单字典。

if do_trade:
    buy_price = mid_price - price_offset  # 计算买价
    buy_price = round(buy_price, self.price_precision)  # 四舍五入买价
    
    sell_price = mid_price + price_offset  # 计算卖价
    sell_price = round(sell_price, self.price_precision)  # 四舍五入卖价

    trade_dict = {
        'do_trade': do_trade,
        'buy_price': buy_price,
        'sell_price': sell_price,
        'amount': trade_amount
    }

    Log('返回盘口挂单字典:', trade_dict)
    return trade_dict
else:
    self.pending_order_count = 0  # 重置挂单次数
  • buy_price:买价,计算为中间价减去价格偏移量。
  • sell_price:卖价,计算为中间价加上价格偏移量。
  • trade_dict:挂单字典,包含买卖价格和数量。

5. 执行盘口交易

根据生成的盘口挂单字典,执行盘口交易。代码中通过调用交易所中间层的 create_order 方法,同时挂出买单和卖单。

def make_trade_by_dict(self, trade_dict):
    if trade_dict['do_trade']:
        buy_id = self.exchange_mid.create_order('buy', trade_dict['buy_price'], trade_dict['amount'])  # 挂买单
        sell_id = self.exchange_mid.create_order('sell', trade_dict['sell_price'], trade_dict['amount'])  # 挂卖单
        
        self.traded_pairs['pan_kou'].append({
            'buy_id': buy_id, 'sell_id': sell_id, 'init_time': time.time(), 'amount': trade_dict['amount']
        })

6. 检查订单状态

定期检查订单状态,处理未完成的订单。订单状态处理逻辑与对敲策略类似,但由于存在价差,部分成交的情况会产生实际的盈利或亏损。

盘口策略的主要缺点

1. 盘口挂单价格移动不够灵活

本策略中的价格调整机制相对简单,存在以下限制:

price_offset = price_range - self.pending_order_count * min_price_step  # 计算价格偏移量
  • 线性调整限制:价格偏移量采用线性递减的方式,无法根据市场实际波动率进行动态调整
  • 参数固化price_rangemin_price_step 是固定参数,不能根据市场状况实时调整
  • 响应迟滞:当市场价格快速变化时,策略的价格调整可能跟不上市场节奏
  • 缺乏市场感知:没有考虑订单簿深度、交易量等市场微观结构因素

改进方向: - 引入基于波动率的动态价格调整机制 - 根据市场深度和流动性调整挂单价格 - 增加对市场趋势的判断,避免逆势挂单

2. 库存风险(Inventory Risk)

盘口策略面临严重的库存风险问题:

风险表现: - 单边成交风险:当只有买单或卖单成交时,会导致持仓不平衡 - 方向性风险:在趋势市场中,可能大量累积单向持仓 - 资金占用:过多的库存会占用大量资金,影响策略效率

代码中的风险点

if buy_order_status['Status'] == ORDER_STATE_PENDING:
    self.sell_amount += traded_pair['amount']  # 只有卖单成交,积累空头持仓
elif sell_order_status['Status'] == ORDER_STATE_PENDING:
    self.buy_amount += traded_pair['amount']  # 只有买单成交,积累多头持仓

库存风险的影响: - 盈利能力下降:单边持仓在不利价格变动时会产生亏损 - 流动性压力:需要额外的资金来对冲库存风险 - 策略失效:极端情况下可能导致策略无法继续运行

风险管理措施: - 库存限制:设置最大持仓限制,防止过度累积 - 动态对冲:当库存超过阈值时,主动平仓或对冲 - 价格倾斜:根据当前库存调整买卖价格,鼓励反向交易

策略总结

盘口策略是一种基于市场深度的做市策略,通过动态调整买卖单的价格和数量,维持市场的流动性。与刷量型对敲策略相比,盘口策略具有以下特点:

✅ 优势 - 通过价差获取真正的套利收益 - 符合传统做市商的盈利模式 - 提供真正的市场流动性

❌ 挑战 - 面临市场价格波动风险 - 需要更复杂的风险管理 - 对资金和技术要求更高 - 价格调整机制不够灵活:线性的价格移动机制难以适应复杂的市场环境 - 库存风险突出:单边成交容易导致持仓不平衡,在趋势市场中风险尤为显著

🔮 未来优化方向

针对当前盘口策略存在的不足,未来可以从以下几个方向进行优化改进:

  1. 动态做市策略

    • 基于市场波动率的自适应价格调整
    • 根据订单簿深度动态调整挂单策略
    • 引入机器学习预测市场方向
  2. 库存管理策略

    • 实时库存监控和风险评估
    • 动态对冲机制和库存平衡算法
    • 基于库存状态的价格倾斜策略
  3. 多层级做市策略

    • 在多个价格层级同时提供流动性
    • 分散单点风险,提高整体稳定性
    • 更接近专业做市商的实际操作
  4. 智能风险管理

    • 实时风险指标监控
    • 自动止损和风险控制机制
    • 市场异常情况的应急处理

策略代码(修正版)

import time, json

class MidClass:
    def __init__(self, exchange_instance):
        '''
        初始化交易所中间层
        
        Args:
            exchange_instance: FMZ的交易所结构
        '''
        self.init_timestamp = time.time()  # 记录初始化时间
        self.exchange = exchange_instance  # 保存交易所对象
        self.exchange_name = self.exchange.GetName()  # 获取交易所名称
        self.trading_pair = self.exchange.GetCurrency()  # 获取交易对名称(如 BTC_USDT)

    def get_precision(self):
        '''
        获取交易对的精度信息
        
        Returns:
            返回包含精度信息的字典,失败时返回 None
        '''
        symbol_code = self.exchange.GetCurrency()
        ticker = self.exchange.GetTicker(symbol_code)  # 回测系统需要
        exchange_info = self.exchange.GetMarkets()
        data = exchange_info.get(symbol_code)

        if not data:
            Log("获取市场信息失败", GetLastError())
            return None

        # 获取该交易对的精度信息
        self.precision_info = {
            'tick_size': data['TickSize'],                  # 价格精度
            'amount_size': data['AmountSize'],              # 数量精度
            'price_precision': data['PricePrecision'],      # 价格小数位精度
            'amount_precision': data['AmountPrecision'],    # 数量小数位精度
            'min_qty': data['MinQty'],                      # 最小下单数量
            'max_qty': data['MaxQty']                       # 最大下单数量
        }

        return self.precision_info

    def get_account(self):
        '''
        获取账户信息
        
        Returns:
            获取信息成功返回 True,获取信息失败返回 False
        '''

        self.balance = '---'  # 账户余额
        self.amount = '---'  # 账户持仓量
        self.frozen_balance = '---'  # 冻结余额
        self.frozen_stocks = '---'  # 冻结持仓量
        self.init_balance = None
        self.init_stocks = None
        self.init_equity = None

        try:
            account_info = self.exchange.GetAccount()  # 获取账户信息
            self.balance = account_info['Balance']  # 更新账户余额
            self.amount = account_info['Stocks']  # 更新持仓量
            self.frozen_balance = account_info['FrozenBalance']  # 更新冻结余额
            self.frozen_stocks = account_info['FrozenStocks']  # 更新冻结持仓量
            self.equity = self.balance + self.frozen_balance + (self.amount + self.frozen_stocks) * self.last_price
            
            if not self.init_balance or not self.init_stocks or not self.init_equity:
                if _G("init_balance") and _G("init_balance") > 0 and _G("init_stocks") and _G("init_stocks") > 0:
                    self.init_balance = round(_G("init_balance"), 2)
                    self.init_stocks = round(_G("init_stocks"), 2)
                    self.init_equity = round(_G("init_equity"), 2)
                else:
                    self.init_balance = round(self.balance + self.frozen_balance, 2)
                    self.init_stocks = self.amount + self.frozen_stocks
                    self.init_equity = round(self.init_balance + (self.init_stocks * self.last_price), 2)
                    _G("init_balance", self.init_balance)
                    _G("init_stocks", self.init_stocks)
                    _G("init_equity", self.init_equity)

                    Log('获取初始eqity', self.init_equity)

            self.profit = self.equity - self.init_equity
            self.profitratio = round((self.equity - self.init_equity)/self.init_equity, 4) * 100

            return True
        except:
            return False  # 获取账户信息失败

    def get_ticker(self):
        '''
        获取市价信息(如买一价、卖一价、最高价、最低价等)
        
        Returns:
            获取信息成功返回 True,获取信息失败返回 False
        '''
        self.high_price = '---'  # 最高价
        self.low_price = '---'  # 最低价
        self.sell_price = '---'  # 卖一价
        self.buy_price = '---'  # 买一价
        self.last_price = '---'  # 最新成交价
        self.volume = '---'  # 成交量
        
        try:
            ticker_info = self.exchange.GetTicker()  # 获取市价信息
        
            self.high_price = ticker_info['High']  # 更新最高价
            self.low_price = ticker_info['Low']  # 更新最低价
            self.sell_price = ticker_info['Sell']  # 更新卖一价
            self.buy_price = ticker_info['Buy']  # 更新买一价
            self.last_price = ticker_info['Last']  # 更新最新成交价
            self.volume = ticker_info['Volume']  # 更新成交量
            return True
        except:
            return False  # 获取市价信息失败
        
    def get_depth(self):
        '''
        获取深度信息(买卖盘的挂单列表)
        
        Returns:
            获取信息成功返回 True,获取信息失败返回 False
        '''
        self.ask_orders = '---'  # 卖盘挂单列表
        self.bid_orders = '---'  # 买盘挂单列表
        
        try:
            depth_info = self.exchange.GetDepth()  # 获取深度信息
            self.ask_orders = depth_info['Asks']  # 更新卖盘挂单列表
            self.bid_orders = depth_info['Bids']  # 更新买盘挂单列表
            return True
        except:
            return False  # 获取深度信息失败
        
    def get_ohlc_data(self, period=PERIOD_M5):
        '''
        获取K线信息
        
        Args:
            period: K线周期,PERIOD_M1 指1分钟, PERIOD_M5 指5分钟, PERIOD_M15 指15分钟,
            PERIOD_M30 指30分钟, PERIOD_H1 指1小时, PERIOD_D1 指一天。
        '''
        self.ohlc_data = self.exchange.GetRecords(period)  # 获取K线数据
        
    def create_order(self, order_type, price, amount):
        '''
        提交一个挂单信息
        
        Args:
            order_type:挂单类型,'buy'指挂买单,'sell'指挂卖单
            price:挂单价格
            amount:挂单数量
            
        Returns:
            挂单Id号,可用以取消挂单
        '''
        if order_type == 'buy':
            try:
                order_id = self.exchange.Buy(price, amount)  # 提交买单
            except:
                return False  # 买单提交失败
            
        elif order_type == 'sell':
            try:
                order_id = self.exchange.Sell(price, amount)  # 提交卖单
            except:
                return False  # 卖单提交失败
        
        return order_id  # 返回订单ID
    
    def get_orders(self):
        '''
        获取未完成的订单列表
        
        Returns:
            未完成的订单列表
        '''
        self.open_orders = self.exchange.GetOrders()  # 获取未完成订单
        return self.open_orders
    
    def cancel_order(self, order_id):
        '''
        取消一个挂单信息
        
        Args:
            order_id:希望取消的挂单ID号
            
        Returns:
            取消挂单成功返回 True,取消挂单失败返回 False
        '''
        return self.exchange.CancelOrder(order_id)  # 取消订单
        
    def refresh_data(self):
        '''
        刷新信息(账户、市价、深度、K线)
        
        Returns:
            刷新信息成功返回 'refresh_data_finish!' 否则返回相应刷新失败的信息提示
        '''

        if not self.get_ticker():  # 刷新市价信息
            return 'false_get_ticker'

        if not self.get_account():  # 刷新账户信息
            return 'false_get_account'
        
        if not self.get_depth():  # 刷新深度信息
            return 'false_get_depth'
        
        try:
            self.get_ohlc_data()  # 刷新K线信息
        except:
            return 'false_get_K_line_info'
        
        return 'refresh_data_finish!'  # 刷新成功


class MarketMaker:
    def __init__(self, mid_class):
        '''
        初始化做市策略
        
        Args:
            mid_class: 交易所中间层对象
        '''
        self.exchange_mid = mid_class  # 交易所中间层对象
        self.precision_info = self.exchange_mid.get_precision()  # 获取精度信息

        self.done_amount = {'pan_kou': 0}  # 已完成交易量
        # 修正:正确分配精度信息
        self.price_precision = self.precision_info['price_precision']  # 价格精度
        self.amount_precision = self.precision_info['amount_precision']  # 交易量精度
        
        self.traded_pairs = {'pan_kou': []}  # 已挂单的交易对
        self.pending_orders = []  # 未完成的订单状态
        self.pending_order_count = 0  # 挂单次数

        self.buy_amount = 0
        self.sell_amount = 0

        self.fee = 0
        self.fee_rate = 0.08 / 100

        self.chart = {
            "__isStock": True,
            "tooltip": {"xDateFormat": "%Y-%m-%d %H:%M:%S, %A"},
            "title": {"text": "挂单数量"},
            "xAxis": {"type": "datetime"},
            "yAxis": {
                "title": {"text": "挂单数量"},
                "opposite": False
            },
            "series": [
                {"name": "挂单买量", "id": "挂单买量", "data": []},
                {"name": "挂单卖量", "id": "挂单卖量", "dashStyle": "shortdash", "data": []}
            ]
        }

    def refresh_data(self):
        '''
        刷新数据(账户、市价、深度、K线)
        '''
        self.exchange_mid.refresh_data()  # 刷新交易所数据
        self.position_amount = 0 if isinstance(self.exchange_mid.amount, str) else self.exchange_mid.amount  # 持仓量
        self.available_balance = 0 if isinstance(self.exchange_mid.balance, str) else self.exchange_mid.balance  # 账户余额

        self.can_buy_amount = self.available_balance / float(self.exchange_mid.buy_price)  # 可买的数量
        self.mid_price = (self.exchange_mid.sell_price + self.exchange_mid.buy_price) / 2  # 中间价

    def make_trade_by_dict(self, trade_dict):
        '''
        根据交易字典执行交易
        
        Args:
            trade_dict: 交易字典
        '''
        Log('4按照字典开始交易')
        self.refresh_data()  # 刷新数据
        
        if trade_dict['do_trade']:
            Log('当前账户资金: 币数余额: ', self.position_amount, '资金余额: ', self.can_buy_amount)
            Log('检查开仓: 币数限制: ', self.position_amount > trade_dict['amount'], '资金限制: ', self.can_buy_amount > trade_dict['amount'])
            if self.position_amount > trade_dict['amount'] and self.can_buy_amount > trade_dict['amount']:
                buy_id = self.exchange_mid.create_order('buy', trade_dict['buy_price'], trade_dict['amount'])  # 挂买单
                sell_id = self.exchange_mid.create_order('sell', trade_dict['sell_price'], trade_dict['amount'])  # 挂卖单
                
                self.traded_pairs['pan_kou'].append({
                    'buy_id': buy_id, 'sell_id': sell_id, 'init_time': time.time(), 'amount': trade_dict['amount']
                })
                    
                self.last_time = time.time()  # 更新上次交易时间
        
    def handle_pending_orders(self):
        '''
        处理未完成的订单
        '''
        pending_orders = self.exchange_mid.get_orders()  # 获取未完成订单
        if len(pending_orders) > 0:
            for order in pending_orders:
                self.exchange_mid.cancel_order(order['Id'])  # 取消未完成订单
                
    def make_pankou_dict(self, price_range, min_price_step, trade_amount):
        
        '''
        生成盘口挂单字典
        
        Args:
            price_range: 价格范围
            min_price_step: 最小价格间隔
            trade_amount: 每次交易量
        
        Returns:
            盘口挂单字典列表
        '''
        Log('3制作盘口挂单字典', '移动盘口次数', self.pending_order_count)
        mid_price = self.mid_price  # 中间价
        
        price_offset = price_range - self.pending_order_count * min_price_step  # 计算价格偏移量
        do_trade = price_offset > 0

        if do_trade:
            buy_price = mid_price - price_offset  # 计算买价
            buy_price = round(buy_price, self.price_precision)  # 四舍五入买价
            
            sell_price = mid_price + price_offset  # 计算卖价
            sell_price = round(sell_price, self.price_precision)  # 四舍五入卖价

            trade_dict = {
                'do_trade': do_trade,
                'buy_price': buy_price,
                'sell_price': sell_price,
                'amount': trade_amount
            }

            Log('返回盘口挂单字典:', trade_dict)
            return trade_dict
        else:
            Log('重置移动盘口次数:', self.pending_order_count)
            self.pending_order_count = 0  # 重置移动盘口次数
            # 修正:当不能交易时返回None或空字典
            return None
            
    
    def check_order_status(self, current_time):
        '''
        检查订单状态
        
        Args:
            current_time: 当前时间戳
        '''
        Log('1开始订单信息检查')
        Log(self.traded_pairs['pan_kou'])
        self.buy_pending = 0
        self.sell_pending = 0
        for traded_pair in self.traded_pairs['pan_kou'].copy():
            Log('检查订单:', traded_pair['buy_id'], traded_pair['sell_id'])

            try:
                buy_order_status = self.exchange_mid.exchange.GetOrder(traded_pair['buy_id'])  # 获取买单状态
                sell_order_status = self.exchange_mid.exchange.GetOrder(traded_pair['sell_id'])  # 获取卖单状态
            except:
                Log(traded_pair, '取消')
                self.exchange_mid.cancel_order(traded_pair['buy_id'])  # 取消买单
                self.exchange_mid.cancel_order(traded_pair['sell_id'])  # 取消卖单
                self.traded_pairs['pan_kou'].remove(traded_pair)  # 移除订单
                return

            Log('检查订单:', traded_pair['buy_id'], buy_order_status, traded_pair['sell_id'], sell_order_status, [sell_order_status['Status'], buy_order_status['Status']])
            if [sell_order_status['Status'], buy_order_status['Status']] == [0, 0]:
                self.buy_pending += 1
                self.sell_pending += 1
                if current_time % 5 == 0:
                    Log('检查挂单,取消挂单(两未完)', buy_order_status['Status'], sell_order_status['Status'], current_time % 5)
                    self.exchange_mid.cancel_order(traded_pair['buy_id'])  # 取消买单
                    self.exchange_mid.cancel_order(traded_pair['sell_id'])  # 取消卖单
                    self.pending_order_count += 1  # 移动盘口次数次数加1
                    self.traded_pairs['pan_kou'].remove(traded_pair)  # 移除订单

            elif {sell_order_status['Status'], buy_order_status['Status']} == {1, 0}:
                if buy_order_status['Status'] == ORDER_STATE_PENDING:
                    self.buy_pending += 1
                if sell_order_status['Status'] == ORDER_STATE_PENDING:
                    self.sell_pending += 1
                if current_time % 5 == 0:
                    Log('检查挂单,取消挂单(一未完)', buy_order_status['Status'], sell_order_status['Status'])
                    self.done_amount['pan_kou'] += traded_pair['amount']  # 更新交易量
                    if buy_order_status['Status'] == ORDER_STATE_PENDING:
                        self.sell_amount += traded_pair['amount']
                        self.fee += sell_order_status['Amount'] * self.fee_rate * sell_order_status['Price']
                        Log('取消该买订单,增加未完成买列表', traded_pair['buy_id'])
                        self.exchange_mid.cancel_order(traded_pair['buy_id'])  # 取消买单
                        self.pending_orders.append(['buy', buy_order_status['Status']])  # 记录未完成订单
                        Log('清除前:', self.traded_pairs['pan_kou'])
                        Log('清除id:', traded_pair)
                        self.traded_pairs['pan_kou'].remove(traded_pair)  # 移除订单
                        Log('清除后:', self.traded_pairs['pan_kou'])
                    elif sell_order_status['Status'] == ORDER_STATE_PENDING:
                        self.buy_amount += traded_pair['amount']
                        self.fee += buy_order_status['Amount'] * self.fee_rate * buy_order_status['Price']
                        Log('取消该卖订单,增加未完成卖列表', traded_pair['sell_id'])
                        self.exchange_mid.cancel_order(traded_pair['sell_id'])  # 取消卖单
                        self.pending_orders.append(['sell', sell_order_status['Status']])  # 记录未完成订单
                        Log('清除前:', self.traded_pairs['pan_kou'])
                        Log('清除id:', traded_pair)
                        self.traded_pairs['pan_kou'].remove(traded_pair)  # 移除订单
                        Log('清除后:', self.traded_pairs['pan_kou'])
                
            elif [sell_order_status['Status'], buy_order_status['Status']] == [1, 1]:
                Log('两订单都已完成')
                Log('完成状态:', buy_order_status['Status'], sell_order_status['Status'], traded_pair['amount'])
                self.done_amount['pan_kou'] += 2 * traded_pair['amount']  # 更新交易量
                self.buy_amount += traded_pair['amount']
                self.sell_amount += traded_pair['amount']
                self.fee += buy_order_status['Amount'] * self.fee_rate * buy_order_status['Price']
                self.fee += sell_order_status['Amount'] * self.fee_rate * sell_order_status['Price']
                self.traded_pairs['pan_kou'].remove(traded_pair)  # 移除订单
            else:
                Log('两订单处于未知状态:', buy_order_status, sell_order_status)
                Log('未知订单状态:', buy_order_status['Status'], sell_order_status['Status'])
                Log('未知订单信息:', traded_pair)

    def update_status(self):

        self.exchange_mid.refresh_data()

        table1 = {
            "type": "table",
            "title": "账户信息",
            "cols": [
                "初始资金", "现存资金", "盘口买入数量", "盘口卖出数量", "费率", "总收益", "收益率"
            ],
            "rows": [
                [   
                    self.exchange_mid.init_equity,
                    self.exchange_mid.equity,
                    round(self.buy_amount, 4),
                    round(self.sell_amount, 4),
                    round(self.fee, 2),
                    self.exchange_mid.profit,
                    str(self.exchange_mid.profitratio) + "%"
                ],
            ],
        }

        LogStatus(
            f"初始化时间: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(self.exchange_mid.init_timestamp))}\n",
            f"`{json.dumps(table1)}`\n",
            f"最后执行时间: {_D()}\n"
        )

        LogProfit(round(self.exchange_mid.profit, 3), '&')

    def plot_pending(self):
        
        Log('盘口挂单数量:', self.buy_pending, self.sell_pending)
        self.obj_chart = Chart(self.chart)
        now_time = int(time.time() * 1000)
        # 更新挂单买量数据
        self.obj_chart.add(0, [now_time, self.buy_pending])
        # 更新挂单卖量数据
        self.obj_chart.add(1, [now_time, self.sell_pending])

def main():
    '''
    主函数,运行做市策略
    '''
    exchange.IO('simulate', True) #OKX现货模拟账户
    exchange.IO("trade_super_margin")

    current_time = 0
    target_amount = 1  # 目标交易量
    
    price_range = 5  # 价格范围
    min_price_step = 1  # 最小价格间隔
    trade_amount = 0.01  # 每次交易量
    
    exchange_mid = MidClass(exchange)  # 初始化交易所中间层
    Log(exchange_mid.refresh_data())  # 刷新数据
    market_maker = MarketMaker(exchange_mid)  # 初始化做市策略
    
    # 修正:初始化trade_dict
    trade_dict = None
    
    while market_maker.done_amount['pan_kou'] < target_amount:  # 循环直到完成目标交易量
        Log(market_maker.traded_pairs['pan_kou'])
        market_maker.check_order_status(current_time)  # 检查订单状态
        Sleep(1000)  # 等待1秒
        market_maker.refresh_data()  # 刷新数据
        
        if len(market_maker.traded_pairs['pan_kou']) < 1: # 价格移动,盘口挂单撤销,等待至所有挂单完毕,制定新的挂单字典
            
            Log('2盘口交易对数量小于1')
            trade_dict = market_maker.make_pankou_dict(price_range, min_price_step, trade_amount)  # 生成盘口挂单字典
            Log('新交易字典', trade_dict)
        
        # 修正:确保trade_dict存在且不为None
        if trade_dict and trade_dict.get('do_trade', False):
            market_maker.make_trade_by_dict(trade_dict)  # 执行交易

        Log('盘口做市数量:', market_maker.done_amount['pan_kou'])  # 记录交易量

        market_maker.plot_pending()
        market_maker.update_status()
        current_time += 1
        
    Log(market_maker.position_amount, market_maker.can_buy_amount)  # 记录持仓量和可买数量
    Log('现存订单:', exchange.GetOrders())  # 记录现存订单

def onexit():
    Log("执行扫尾函数")

    _G("init_balance", None)
    _G("init_stocks", None)
    _G("init_equity", None)
相关推荐