avatar of 发明者量化-小小梦 发明者量化-小小梦
关注 私信
4
关注
1271
关注者

A Brief Discussion on Digital Currency Market Making Strategies (2): Order Book Strategies

创建于: 2025-08-04 14:55:54, 更新于: 2025-08-04 15:19:28
comments   0
hits   146

A Brief Discussion on Digital Currency Market Making Strategies (2): Order Book Strategies

Preface

In our previous article “Wash Trading Strategies in Digital Currency,” we provided a detailed introduction to a strategy framework that accumulates trading volume through same-price buy and sell orders. The primary objective of this strategy is to obtain exchange rebates or tier benefits, rather than generating profits through price spread arbitrage. While wash trading strategies have reference value for learning trading framework architecture, their actual profit-making capability is limited and may face compliance risks. Building upon the previous article, this piece will introduce another market making strategy with greater practical value—Order Book Strategy. Unlike wash trading strategies, the order book strategy is a genuine arbitrage strategy that generates profits by setting price spreads between bid and ask prices, which better aligns with the traditional market maker profit model.

⚠️Important Disclaimer

The order book strategy code presented in this article is solely for learning reference framework purposes and does not have any live trading experience. The strategy implementation in this article is intended only for technical learning and research purposes and has not been thoroughly validated in actual market environments. Readers must conduct comprehensive backtesting verification and risk assessment when referencing the content of this article, and should never use it directly for live trading.

Order Book Strategy Principles

The order book strategy is a market-making strategy that leverages the market order book (i.e., market depth) for arbitrage. Under this strategy, market makers dynamically adjust order prices within the bid-ask spread based on market fluctuations, executing order placement and cancellation operations to profit from market liquidity and short-term price volatility.

Core Features

  1. Dynamic Order Price Adjustment: Dynamically adjust bid and ask order prices based on market depth and price volatility to improve execution probability.
  2. Order Quantity Control: Control order quantities based on account funds and position status to avoid excessive exposure to market risks.
  3. Order Status Management: Regularly monitor order status and handle unfilled orders.

Differences from Wash Trading Strategies

Feature Wash Trading Strategy Order Book Strategy
Buy/Sell Prices Same price Different prices (with spread)
Profit Model Exchange rebates/incentives Bid-ask spread
Risk Exposure Low (same-price execution) High (price volatility risk)
Practicality Limited Higher

Advantages of Order Book Strategy

Improve Market Liquidity: By placing orders in the order book, it increases market depth on both buy and sell sides, attracting more traders to participate. Earn Bid-Ask Spread: By providing liquidity, market makers can earn the bid-ask spread and generate profits. Flexible Response to Market Volatility: The order book strategy can dynamically adjust order prices based on market fluctuations, reducing market risk.

Challenges of Order Book Strategy

Market Risk: Market price volatility may prevent market makers’ orders from being executed, potentially causing losses. Capital Pressure: Market makers need sufficient capital to maintain order book depth on both sides; insufficient funds may render the strategy ineffective. Complex Order Management: The order book strategy requires regular monitoring of order status and handling of unfilled orders, adding complexity to the strategy.

Order Book Strategy Structure

Consistent with the wash trading strategy, the code implementation in this article presents a market-making strategy based on the order book approach, primarily divided into two classes:

  • MidClass: Exchange middleware layer, responsible for interfacing with exchange APIs, obtaining market data, account information, order status, etc.
  • MarketMaker: Market making strategy class, responsible for executing the order book strategy, dynamically generating order prices, placing orders, checking order status, updating strategy state, etc.

Order Book Strategy Workflow

1. Initialization

In the initialization method of the MarketMaker class, exchange precision information is first obtained and strategy parameters are initialized, such as volume precision, price precision, etc.

self.precision_info = self.exchange_mid.get_precision()  # Get precision information
self.price_precision = self.precision_info['price_precision']  # Price precision
self.amount_precision = self.precision_info['amount_precision']  # Volume precision

2. Generate Order Book Dictionary

The core of the order book strategy is generating the order book dictionary, which contains bid/ask prices and quantities. The code generates the order book dictionary by calculating the mid-price and price offsets.

3. Order Book Price Movement

Order book price movement is achieved by calculating price offsets. The price offset is calculated based on the price range (price_range) and minimum price step (min_price_step).

price_offset = price_range - self.pending_order_count * min_price_step  # Calculate price offset
do_trade = price_offset > 0
  • price_range: Price range, representing the deviation range of order prices from the mid-price.
  • min_price_step: Minimum price step, representing the minimum adjustment increment for each order price.
  • price_offset: Price offset, representing the current deviation of order prices from the mid-price.

If the price offset is greater than 0, it indicates that orders can continue to be placed; otherwise, the pending order count is reset.

4. Generate Order Dictionary

Based on the price offset, calculate bid and ask prices, and generate the order dictionary.

if do_trade:
   buy_price = mid_price - price_offset  # Calculate buy price
   buy_price = round(buy_price, self.price_precision)  # Round buy price
   
   sell_price = mid_price + price_offset  # Calculate sell price
   sell_price = round(sell_price, self.price_precision)  # Round sell price
   trade_dict = {
       'do_trade': do_trade,
       'buy_price': buy_price,
       'sell_price': sell_price,
       'amount': trade_amount
   }
   Log('Return order book dictionary:', trade_dict)
   return trade_dict
else:
   self.pending_order_count = 0  # Reset pending order count
  • buy_price: Buy price, calculated as mid-price minus price offset.
  • sell_price: Sell price, calculated as mid-price plus price offset.
  • trade_dict: Order dictionary, containing bid/ask prices and quantities.

5. Execute Order Book Trading

Based on the generated order book dictionary, execute order book trading. The code simultaneously places buy and sell orders by calling the create_order method of the exchange middleware layer.

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'])     # Place Buy Order
        sell_id = self.exchange_mid.create_order('sell', trade_dict['sell_price'], trade_dict['amount'])  # Place Sell Order
        
        self.traded_pairs['pan_kou'].append({
            'buy_id': buy_id, 'sell_id': sell_id, 'init_time': time.time(), 'amount': trade_dict['amount']
        })

6. Check Order Status

Regularly check the status of orders and handle incomplete ones. The logic for processing order status is similar to the arbitrage strategy, but due to price differences, partial fills may result in actual profits or losses.

Main Drawbacks of the Order Book Strategy

1、Order book placement price adjustment is not flexible enough

The price adjustment mechanism in this strategy is relatively simple and has the following limitations:

price_offset = price_range - self.pending_order_count * min_price_step # calculate price offset
  • Linear Adjustment Limitation: The price offset uses a linearly decreasing method, which cannot dynamically adjust based on actual market volatility
  • Parameter Fixation: price_range and min_price_step are fixed parameters and cannot be adjusted in real-time according to market conditions
  • Lag in Response: When market prices change rapidly, the strategy’s price adjustment may not keep pace with the market
  • Lack of Market Awareness: Does not take into account microstructure factors such as order book depth or trading volume

Improvement Directions:

  • Introduce a volatility-based dynamic price adjustment mechanism

  • Adjust order placement prices based on market depth and liquidity

  • Incorporate market trend analysis to avoid placing orders against the trend

2、Inventory Risk

The order book strategy faces serious inventory risk issues:

Risk Manifestations:

  • One-sided Fill Risk: When only buy or sell orders are filled, it leads to an imbalanced position

  • Directional Risk: In trending markets, large one-sided positions may accumulate

  • Capital Occupancy: Excessive inventory occupies a large amount of capital, reducing strategy efficiency

Risk Points in the Code:

if buy_order_status['Status'] == ORDER_STATE_PENDING:
    self.sell_amount += traded_pair['amount']  # Only the sell order is filled, accumulating short positions
elif sell_order_status['Status'] == ORDER_STATE_PENDING:
    self.buy_amount += traded_pair['amount']  # Only the buy order is filled, accumulating long positions

Impact of Inventory Risk:

  • Decline in Profitability: One-sided positions may incur losses when prices move unfavorably

  • Liquidity Pressure: Additional capital is required to hedge inventory risk

  • Strategy Failure: In extreme cases, the strategy may become inoperable

Risk Management Measures:

  • Inventory Limits: Set maximum position limits to prevent excessive accumulation

  • Dynamic Hedging: Actively close or hedge positions when inventory exceeds a threshold

  • Price Skewing: Adjust buy/sell prices based on current inventory to encourage offsetting trades

Strategy Summary

The order book strategy is a market-making approach based on market depth. It maintains liquidity by dynamically adjusting the price and quantity of buy and sell orders. Compared to wash-trade-based arbitrage strategies, the order book strategy has the following characteristics:

✅ Advantages

  • Earns true arbitrage profits from price spreads

  • Aligns with the traditional market maker profit model

  • Provides genuine market liquidity

❌ Challenges

  • Faces market price fluctuation risks

  • Requires more sophisticated risk management

  • Demands higher capital and technical capabilities

  • Inflexible price adjustment mechanism: linear price movement is hard to adapt to complex market conditions

  • Significant inventory risk: one-sided fills easily lead to unbalanced positions, especially in trending markets

🔮 Future Optimization Directions

To address the current limitations of the order book strategy, future improvements can focus on the following areas:

  • Dynamic Market-Making Strategies:

    • Adaptive price adjustment based on market volatility

    • Dynamic order placement adjustment using order book depth

    • Incorporate machine learning to predict market direction

  • Inventory Management Strategies:

    • Real-time inventory monitoring and risk assessment

    • Dynamic hedging mechanisms and inventory balancing algorithms

    • Price skewing strategies based on inventory status

  • Multi-Level Market-Making:

    • Provide liquidity at multiple price levels simultaneously

    • Diversify point risk and improve overall stability

    • Closer to the actual operations of professional market makers

  • Intelligent Risk Management:

    • Real-time risk metric monitoring

    • Automatic stop-loss and risk control mechanisms

    • Emergency handling for abnormal market conditions

Strategy Code (Revised Version):

import time, json

class MidClass:
    def __init__(self, exchange_instance):
        '''
        Initialize exchange middleware
        
        Args:
            exchange_instance: FMZ exchange structure
        '''
        self.init_timestamp = time.time()  # Record initialization time
        self.exchange = exchange_instance  # Save exchange object
        self.exchange_name = self.exchange.GetName()  # Get exchange name
        self.trading_pair = self.exchange.GetCurrency()  # Get trading pair name (e.g., BTC_USDT)

    def get_precision(self):
        '''
        Get precision information for the trading pair
        
        Returns:
            Returns dictionary containing precision information, returns None on failure
        '''
        symbol_code = self.exchange.GetCurrency()
        ticker = self.exchange.GetTicker(symbol_code)  # Required for backtesting system
        exchange_info = self.exchange.GetMarkets()
        data = exchange_info.get(symbol_code)

        if not data:
            Log("Failed to get market information", GetLastError())
            return None

        # Get precision information for this trading pair
        self.precision_info = {
            'tick_size': data['TickSize'],                  # Price precision
            'amount_size': data['AmountSize'],              # Quantity precision
            'price_precision': data['PricePrecision'],      # Price decimal precision
            'amount_precision': data['AmountPrecision'],    # Quantity decimal precision
            'min_qty': data['MinQty'],                      # Minimum order quantity
            'max_qty': data['MaxQty']                       # Maximum order quantity
        }

        return self.precision_info

    def get_account(self):
        '''
        Get account information
        
        Returns:
            Returns True if information retrieved successfully, False if failed
        '''

        self.balance = '---'  # Account balance
        self.amount = '---'  # Account position
        self.frozen_balance = '---'  # Frozen balance
        self.frozen_stocks = '---'  # Frozen position
        self.init_balance = None
        self.init_stocks = None
        self.init_equity = None

        try:
            account_info = self.exchange.GetAccount()  # Get account information
            self.balance = account_info['Balance']  # Update account balance
            self.amount = account_info['Stocks']  # Update position
            self.frozen_balance = account_info['FrozenBalance']  # Update frozen balance
            self.frozen_stocks = account_info['FrozenStocks']  # Update frozen position
            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('Get initial equity', 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  # Failed to get account information

    def get_ticker(self):
        '''
        Get market price information (such as best bid, best ask, high, low, etc.)
        
        Returns:
            Returns True if information retrieved successfully, False if failed
        '''
        self.high_price = '---'  # High price
        self.low_price = '---'  # Low price
        self.sell_price = '---'  # Best ask price
        self.buy_price = '---'  # Best bid price
        self.last_price = '---'  # Last trade price
        self.volume = '---'  # Volume
        
        try:
            ticker_info = self.exchange.GetTicker()  # Get market price information
        
            self.high_price = ticker_info['High']  # Update high price
            self.low_price = ticker_info['Low']  # Update low price
            self.sell_price = ticker_info['Sell']  # Update best ask price
            self.buy_price = ticker_info['Buy']  # Update best bid price
            self.last_price = ticker_info['Last']  # Update last trade price
            self.volume = ticker_info['Volume']  # Update volume
            return True
        except:
            return False  # Failed to get market price information
        
    def get_depth(self):
        '''
        Get depth information (order book of buy and sell orders)
        
        Returns:
            Returns True if information retrieved successfully, False if failed
        '''
        self.ask_orders = '---'  # Ask order list
        self.bid_orders = '---'  # Bid order list
        
        try:
            depth_info = self.exchange.GetDepth()  # Get depth information
            self.ask_orders = depth_info['Asks']  # Update ask order list
            self.bid_orders = depth_info['Bids']  # Update bid order list
            return True
        except:
            return False  # Failed to get depth information
        
    def get_ohlc_data(self, period=PERIOD_M5):
        '''
        Get K-line information
        
        Args:
            period: K-line period, PERIOD_M1 for 1 minute, PERIOD_M5 for 5 minutes, PERIOD_M15 for 15 minutes,
            PERIOD_M30 for 30 minutes, PERIOD_H1 for 1 hour, PERIOD_D1 for one day.
        '''
        self.ohlc_data = self.exchange.GetRecords(period)  # Get K-line data
        
    def create_order(self, order_type, price, amount):
        '''
        Submit an order
        
        Args:
            order_type: Order type, 'buy' for buy order, 'sell' for sell order
            price: Order price
            amount: Order quantity
            
        Returns:
            Order ID, can be used to cancel order
        '''
        if order_type == 'buy':
            try:
                order_id = self.exchange.Buy(price, amount)  # Submit buy order
            except:
                return False  # Buy order submission failed
            
        elif order_type == 'sell':
            try:
                order_id = self.exchange.Sell(price, amount)  # Submit sell order
            except:
                return False  # Sell order submission failed
        
        return order_id  # Return order ID
    
    def get_orders(self):
        '''
        Get list of pending orders
        
        Returns:
            List of pending orders
        '''
        self.open_orders = self.exchange.GetOrders()  # Get pending orders
        return self.open_orders
    
    def cancel_order(self, order_id):
        '''
        Cancel an order
        
        Args:
            order_id: Order ID to cancel
            
        Returns:
            Returns True if order cancellation successful, False if failed
        '''
        return self.exchange.CancelOrder(order_id)  # Cancel order
        
    def refresh_data(self):
        '''
        Refresh information (account, market price, depth, K-line)
        
        Returns:
            Returns 'refresh_data_finish!' if refresh successful, otherwise returns corresponding refresh failure message
        '''

        if not self.get_ticker():  # Refresh market price information
            return 'false_get_ticker'

        if not self.get_account():  # Refresh account information
            return 'false_get_account'
        
        if not self.get_depth():  # Refresh depth information
            return 'false_get_depth'
        
        try:
            self.get_ohlc_data()  # Refresh K-line information
        except:
            return 'false_get_K_line_info'
        
        return 'refresh_data_finish!'  # Refresh successful


class MarketMaker:
    def __init__(self, mid_class):
        '''
        Initialize market making strategy
        
        Args:
            mid_class: Exchange middleware object
        '''
        self.exchange_mid = mid_class  # Exchange middleware object
        self.precision_info = self.exchange_mid.get_precision()  # Get precision information

        self.done_amount = {'pan_kou': 0}  # Completed trade volume
        # Fix: Correctly assign precision information
        self.price_precision = self.precision_info['price_precision']  # Price precision
        self.amount_precision = self.precision_info['amount_precision']  # Trade volume precision
        
        self.traded_pairs = {'pan_kou': []}  # Placed trading pairs
        self.pending_orders = []  # Pending order status
        self.pending_order_count = 0  # Order placement count

        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": "Pending Order Quantity"},
            "xAxis": {"type": "datetime"},
            "yAxis": {
                "title": {"text": "Pending Order Quantity"},
                "opposite": False
            },
            "series": [
                {"name": "Pending Buy Volume", "id": "Pending Buy Volume", "data": []},
                {"name": "Pending Sell Volume", "id": "Pending Sell Volume", "dashStyle": "shortdash", "data": []}
            ]
        }

    def refresh_data(self):
        '''
        Refresh data (account, market price, depth, K-line)
        '''
        self.exchange_mid.refresh_data()  # Refresh exchange data
        self.position_amount = 0 if isinstance(self.exchange_mid.amount, str) else self.exchange_mid.amount  # Position amount
        self.available_balance = 0 if isinstance(self.exchange_mid.balance, str) else self.exchange_mid.balance  # Account balance

        self.can_buy_amount = self.available_balance / float(self.exchange_mid.buy_price)  # Buyable quantity
        self.mid_price = (self.exchange_mid.sell_price + self.exchange_mid.buy_price) / 2  # Mid price

    def make_trade_by_dict(self, trade_dict):
        '''
        Execute trade according to trade dictionary
        
        Args:
            trade_dict: Trade dictionary
        '''
        Log('4Start trading according to dictionary')
        self.refresh_data()  # Refresh data
        
        if trade_dict['do_trade']:
            Log('Current account funds: Coin balance: ', self.position_amount, 'Fund balance: ', self.can_buy_amount)
            Log('Check position opening: Coin limit: ', self.position_amount > trade_dict['amount'], 'Fund limit: ', 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'])  # Place buy order
                sell_id = self.exchange_mid.create_order('sell', trade_dict['sell_price'], trade_dict['amount'])  # Place sell order
                
                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()  # Update last trade time
        
    def handle_pending_orders(self):
        '''
        Handle pending orders
        '''
        pending_orders = self.exchange_mid.get_orders()  # Get pending orders
        if len(pending_orders) > 0:
            for order in pending_orders:
                self.exchange_mid.cancel_order(order['Id'])  # Cancel pending orders
                
    def make_pankou_dict(self, price_range, min_price_step, trade_amount):
        
        '''
        Generate order book dictionary
        
        Args:
            price_range: Price range
            min_price_step: Minimum price step
            trade_amount: Trade amount per transaction
        
        Returns:
            Order book dictionary list
        '''
        Log('3Create order book dictionary', 'Move order book count', self.pending_order_count)
        mid_price = self.mid_price  # Mid price
        
        price_offset = price_range - self.pending_order_count * min_price_step  # Calculate price offset
        do_trade = price_offset > 0

        if do_trade:
            buy_price = mid_price - price_offset  # Calculate buy price
            buy_price = round(buy_price, self.price_precision)  # Round buy price
            
            sell_price = mid_price + price_offset  # Calculate sell price
            sell_price = round(sell_price, self.price_precision)  # Round sell price

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

            Log('Return order book dictionary:', trade_dict)
            return trade_dict
        else:
            Log('Reset move order book count:', self.pending_order_count)
            self.pending_order_count = 0  # Reset move order book count
            # Fix: Return None or empty dictionary when cannot trade
            return None
            
    
    def check_order_status(self, current_time):
        '''
        Check order status
        
        Args:
            current_time: Current timestamp
        '''
        Log('1Start order information check')
        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('Check order:', traded_pair['buy_id'], traded_pair['sell_id'])

            try:
                buy_order_status = self.exchange_mid.exchange.GetOrder(traded_pair['buy_id'])  # Get buy order status
                sell_order_status = self.exchange_mid.exchange.GetOrder(traded_pair['sell_id'])  # Get sell order status
            except:
                Log(traded_pair, 'Cancel')
                self.exchange_mid.cancel_order(traded_pair['buy_id'])  # Cancel buy order
                self.exchange_mid.cancel_order(traded_pair['sell_id'])  # Cancel sell order
                self.traded_pairs['pan_kou'].remove(traded_pair)  # Remove order
                return

            Log('Check order:', 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('Check pending orders, cancel orders (both pending)', buy_order_status['Status'], sell_order_status['Status'], current_time % 5)
                    self.exchange_mid.cancel_order(traded_pair['buy_id'])  # Cancel buy order
                    self.exchange_mid.cancel_order(traded_pair['sell_id'])  # Cancel sell order
                    self.pending_order_count += 1  # Increment move order book count
                    self.traded_pairs['pan_kou'].remove(traded_pair)  # Remove order

            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('Check pending orders, cancel orders (one pending)', buy_order_status['Status'], sell_order_status['Status'])
                    self.done_amount['pan_kou'] += traded_pair['amount']  # Update trade volume
                    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('Cancel this buy order, add to pending buy list', traded_pair['buy_id'])
                        self.exchange_mid.cancel_order(traded_pair['buy_id'])  # Cancel buy order
                        self.pending_orders.append(['buy', buy_order_status['Status']])  # Record pending order
                        Log('Before clearing:', self.traded_pairs['pan_kou'])
                        Log('Clear id:', traded_pair)
                        self.traded_pairs['pan_kou'].remove(traded_pair)  # Remove order
                        Log('After clearing:', 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('Cancel this sell order, add to pending sell list', traded_pair['sell_id'])
                        self.exchange_mid.cancel_order(traded_pair['sell_id'])  # Cancel sell order
                        self.pending_orders.append(['sell', sell_order_status['Status']])  # Record pending order
                        Log('Before clearing:', self.traded_pairs['pan_kou'])
                        Log('Clear id:', traded_pair)
                        self.traded_pairs['pan_kou'].remove(traded_pair)  # Remove order
                        Log('After clearing:', self.traded_pairs['pan_kou'])
                
            elif [sell_order_status['Status'], buy_order_status['Status']] == [1, 1]:
                Log('Both orders completed')
                Log('Completion status:', buy_order_status['Status'], sell_order_status['Status'], traded_pair['amount'])
                self.done_amount['pan_kou'] += 2 * traded_pair['amount']  # Update trade volume
                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)  # Remove order
            else:
                Log('Both orders in unknown status:', buy_order_status, sell_order_status)
                Log('Unknown order status:', buy_order_status['Status'], sell_order_status['Status'])
                Log('Unknown order information:', traded_pair)

    def update_status(self):

        self.exchange_mid.refresh_data()

        table1 = {
            "type": "table",
            "title": "Account Information",
            "cols": [
                "Initial Capital", "Current Capital", "Order Book Buy Quantity", "Order Book Sell Quantity", "Fee Rate", "Total Profit", "Profit Rate"
            ],
            "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"Initialization time: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(self.exchange_mid.init_timestamp))}\n",
            f"`{json.dumps(table1)}`\n",
            f"Last execution time: {_D()}\n"
        )

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

    def plot_pending(self):
        
        Log('Order book pending quantity:', self.buy_pending, self.sell_pending)
        self.obj_chart = Chart(self.chart)
        now_time = int(time.time() * 1000)
        # Update pending buy volume data
        self.obj_chart.add(0, [now_time, self.buy_pending])
        # Update pending sell volume data
        self.obj_chart.add(1, [now_time, self.sell_pending])

def main():
    '''
    Main function, run market making strategy
    '''
    exchange.IO('simulate', True) #OKX spot simulation account
    exchange.IO("trade_super_margin")

    current_time = 0
    target_amount = 1  # Target trade volume
    
    price_range = 5  # Price range
    min_price_step = 1  # Minimum price step
    trade_amount = 0.01  # Trade amount per transaction
    
    exchange_mid = MidClass(exchange)  # Initialize exchange middleware
    Log(exchange_mid.refresh_data())  # Refresh data
    market_maker = MarketMaker(exchange_mid)  # Initialize market making strategy
    
    # Fix: Initialize trade_dict
    trade_dict = None
    
    while market_maker.done_amount['pan_kou'] < target_amount:  # Loop until target trade volume completed
        Log(market_maker.traded_pairs['pan_kou'])
        market_maker.check_order_status(current_time)  # Check order status
        Sleep(1000)  # Wait 1 second
        market_maker.refresh_data()  # Refresh data
        
        if len(market_maker.traded_pairs['pan_kou']) < 1: # Price movement, order book orders cancelled, wait until all orders completed, create new order dictionary
            
            Log('2Order book trading pair quantity less than 1')
            trade_dict = market_maker.make_pankou_dict(price_range, min_price_step, trade_amount)  # Generate order book dictionary
            Log('New trade dictionary', trade_dict)
        
        # Fix: Ensure trade_dict exists and is not None
        if trade_dict and trade_dict.get('do_trade', False):
            market_maker.make_trade_by_dict(trade_dict)  # Execute trade

        Log('Order book market making quantity:', market_maker.done_amount['pan_kou'])  # Record trade volume

        market_maker.plot_pending()
        market_maker.update_status()
        current_time += 1
        
    Log(market_maker.position_amount, market_maker.can_buy_amount)  # Record position amount and buyable quantity
    Log('Existing orders:', exchange.GetOrders())  # Record existing orders

def onexit():
    Log("Execute cleanup function")

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