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

Python多币种量化策略框架:设计思路与实现详解

创建于: 2025-08-29 13:10:54, 更新于: 2025-08-31 09:11:53
comments   0
hits   626

[TOC]

Python多币种量化策略框架:设计思路与实现详解

引言:

近期,有用户在小草老师《FMZ升级后,如何快捷构建通用多币种交易策略》一文的评论区留言,希望能够提供该策略框架的Python实现版本。为了满足广大Python开发者的需求,本文将在小草老师原有思路的基础上,结合币安模拟交易环境,详细讲解如何构建一套通用的多币种量化交易框架。

本框架具有以下特点: - 基于Python语言,易于理解和扩展 - 支持多币种并发交易 - 采用币安模拟交易所进行安全测试 - 提供完整的代码示例和详细注释

希望通过本文的分享,能够帮助大家快速上手多币种量化交易开发。同时也欢迎各位开发者在此基础上进行创新优化,打造出更加完善的个性化交易策略。让我们一起在量化交易的道路上不断探索前行!

初始化策略

在交易策略的初始化阶段,我们首先定义了全局变量SYMBOLSQUOTOINTERVAL,代表目标交易币种,基础货币和间隔时间,Info变量用于存储策略运行过程中所需的所有关键数据。接着,通过 InitInfo 函数对这些数据进行初始化,包括账户信息、时间管理、每个交易币种的行情数据、订单信息、仓位信息等。这些初始化步骤确保了策略在运行时有清晰的数据结构和初始状态,为后续的策略执行奠定了基础。

import time
import json 

SYMBOLS = 'LINK,ETH,TRB'
QUOTO = 'USDT'
INTERVAL = 5

# 全局变量,储存数据
# SYMBOLS代表要交易的币种,格式如"BTC,ETH,LTC"
# QUOTO为基础货币,永续合约常见的有USDT,USDC
# INTERVAL代表循环的间隔
Info = {
    'trade_symbols': SYMBOLS.split(','),  # 交易币种
    'base_coin': QUOTO,                   # 基础货币
    'ticker': {},                         # 行情数据
    'order': {},                          # 订单信息
    'account': {},                        # 账户信息
    'precision': {},                      # 精度信息
    'position': {},                       # 仓位信息
    'time': {},                           # 时间相关数据
    'count': {},                          # 计数器
    'interval': INTERVAL                  # 循环的间隔时间
}

# 初始化策略
def InitInfo():

    # 初始化账户信息,初始余额为0
    Info['account'] = {
        'init_balance': 0,  # 初始余额
        'wallet_balance': 0,  # 钱包余额
        'margin_balance': 0,  # 保证金余额
        'margin_used': 0,  # 已用保证金
        'margin_free': 0,  # 可用保证金
        'profit': 0,  # 总收益
        'profit_rate': 0,  # 收益率
        'unrealised_profit': 0,  # 未实现收益
    }

    # 初始化时间数据,控制更新的时间
    Info['time'] = {
        'update_ticker_time': 0,    # 更新行情的时间
        'update_pos_time': 0,       # 更新仓位的时间
        'update_profit_time': 0,    # 更新利润的时间
        'update_account_time': 0,   # 更新账户信息的时间
        'update_status_time': 0,    # 更新状态的时间
        'last_loop_time': 0,        # 上一次主循环的时间
        'loop_delay': 0,             # 循环延迟
        'start_time': time.time()
    }

    # 初始化每个交易币种的数据
    for symbol in Info['trade_symbols']:
        Info['ticker'][symbol] = {'last': 0, 'ask': 0, 'bid': 0}  # 行情
        Info['order'][symbol] = {                                 # 订单信息
            'buy': {'id': 0, 'price': 0, 'amount': 0},
            'sell': {'id': 0, 'price': 0, 'amount': 0}
        }
        Info['position'][symbol] = {                              # 仓位信息
            'amount': 0, 'hold_price': 0, 'unrealised_profit': 0, 'open_time': 0, 'value': 0
        }
        Info['precision'][symbol] = {}  # 精度信息初始化为空
        Info['position'][symbol] = {                              # 仓位信息
            'amount': 0, 'hold_price': 0, 'unrealised_profit': 0, 'open_time': 0, 'value': 0
        }

获取市场信息与精度设置

这一步骤确保我们所处理的币种在价格、数量等方面的精度和下单数量符合交易所的标准。不同的交易对(如BTC/USD或ETH/USDT)在价格和数量的最小精度不同,因此需要根据交易所API获取精度信息,避免订单不合规。例如,ETH/USDT可能允许两位小数,但BTC/USDT可能允许八位小数。

目的: - 获取每个币种的价格和数量精度,确保订单数据的正确性。 - 防止由于精度错误而导致的订单失败。

# 获取精度信息
def GetPrecision():
    # 获取交易所的市场信息
    for presym in Info['trade_symbols']:
        curcontract = presym + '_USDT.swap'
        exchange.GetTicker(curcontract)
    exchange_info = exchange.GetMarkets()
    
    # 遍历市场中的所有交易对
    for pair, data in exchange_info.items():
        symbol = pair.split('_')[0]  # 永续合约交易对的格式为 BTC_USDT.swap
        
        # 检查该交易对是否为我们要交易的币种,基础货币是否匹配,且是永续合约
        if symbol in Info['trade_symbols'] and pair.split('.')[0].endswith(Info['base_coin']) and pair.endswith('swap'):
            # 获取该交易对的精度信息
            Info['precision'][symbol] = {
                'tick_size': data['TickSize'],                  # 价格精度
                'amount_size': data['AmountSize'],              # 数量精度
                'price_precision': data['PricePrecision'],      # 价格小数位精度
                'amount_precision': data['AmountPrecision'],    # 数量小数位精度
                'min_qty': data['MinQty'],                      # 最小下单数量
                'max_qty': data['MaxQty'],                      # 最大下单数量
                'min_notional': data['MinNotional'],            # 最小交易额
                'ctVal': data['CtVal']                          # 合约价值,如1张代表0.01个币
            }
            
            # 检查合约价值的计价货币是否为symbol,避免币本位情况
            if data['CtValCcy'] != symbol:
                raise Exception("不支持币本位")

GetPrecision函数: - 通过API获取交易所的市场信息,包括交易对的精度设置。 - 对于符合条件的交易对,记录其价格精度、数量精度、最小最大交易量和合约价值等信息。 - 检查是否为币本位交易,如果是则抛出异常。

获取行情

通过API接口获取当前的市场数据,如最新价格、买一价、卖一价、买卖盘深度等。这些信息是后续交易决策的重要依据。根据不同的策略,这些数据可以是基于K线的(OHLC数据)或者逐笔交易的(tick数据)。

目的: - 获取当前市场的最新交易数据,以便策略依据这些数据进行买卖决策。 - 包含实时和历史数据的获取,用于技术指标计算。

# 更新行情信息
def UpdateTicker():
    
    # 记录当前更新时间戳
    Info['time']['update_ticker_time'] = time.time() * 1000 # 使用time.time()获取当前时间的时间戳
    
    # 遍历获取到的行情数据
    for ticpre in Info['trade_symbols']:
        
        curcontract = ticpre + '_' + QUOTO + '.swap'
        data = exchange.GetTicker(curcontract)
        
        if not data:
            Log("获取行情失败", GetLastError())
            return
        # 提取交易币种,永续合约格式如 'BTC_USDT.swap',这里取币种名 'BTC'
        symbol = data['Symbol'].split('_')[0]
        
        # 过滤掉不是基础货币(Info['base_coin'])的交易对或不是永续合约的交易对
        if not data['Symbol'].split('.')[0].endswith(Info['base_coin']) or symbol not in Info['trade_symbols'] or not data['Symbol'].endswith('swap'):
            continue
        
        # 更新行情的卖出价、买入价和最后成交价
        Info['ticker'][symbol]['ask'] = float(data['Sell'])  # 卖出价
        Info['ticker'][symbol]['bid'] = float(data['Buy'])   # 买入价
        Info['ticker'][symbol]['last'] = float(data['Last']) # 最后成交价
  1. 获取行情数据

    • 使用exchange.GetTickers获取所有交易对的实时行情信息。ticker变量保存了所有的交易对信息。
  2. 错误处理

    • 如果无法成功获取行情数据,程序通过Log函数记录日志并输出GetLastError返回的错误信息。
  3. 更新时间

    • 使用time.time来记录当前时间的时间戳,用于标记行情更新的时间。
  4. 数据过滤

    • 提取行情数据中的交易币种名称。
    • 过滤掉不符合条件的交易对,例如不以基础货币结算的交易对,或不是永续合约的交易对。
  5. 更新行情数据

    • 对于符合条件的交易币种,更新其买入价、卖出价以及最后成交价。

通过该函数,系统能够实时获取并更新目标交易币种的最新行情信息。

获取账户仓位信息

通过API获取账户的余额和当前持仓情况(已买入的币种、数量、成本价格等)。这一步非常关键,用于评估可用的资金、计算风险和管理仓位。例如,当前的持仓决定了是否要加仓或减仓。

目的: - 确保账户内有足够资金或持仓以执行交易。 - 根据账户当前的仓位和资金情况,决定交易的大小和方向。

# 更新账户信息
def UpdateAccount():
   
    # 如果上次更新时间距现在不到1分钟,直接返回
    if time.time() - Info['time']['update_account_time'] < 60:
        return
    
    # 记录账户信息更新时间
    Info['time']['update_account_time'] = time.time() * 1000
    
    # 获取账户信息
    account = exchange.GetAccount()
    
    # 如果账户信息获取失败,记录日志并返回
    if account is None:
        Log("更新账户失败")
        return
    
    # 计算账户信息
    Info['account']['margin_used'] = round(account['Equity'] - account['Balance'], 2)  # 使用的保证金
    Info['account']['margin_balance'] = round(account['Equity'], 2)  # 当前账户余额
    Info['account']['margin_free'] = round(account['Balance'], 2)  # 可用余额
    Info['account']['wallet_balance'] = round(account['Equity'] - account['UPnL'], 2)  # 钱包余额
    Info['account']['unrealised_profit'] = round(account['UPnL'], 2)  # 未实现盈亏

    # 初始化账户初始余额
    if not Info['account']['init_balance']:
        if _G("init_balance") and _G("init_balance") > 0:
            Info['account']['init_balance'] = round(_G("init_balance"), 2)
        else:
            Info['account']['init_balance'] = Info['account']['margin_balance']
            _G("init_balance", Info['account']['init_balance'])
    
    # 计算账户利润及利润率
    Info['account']['profit'] = round(Info['account']['margin_balance'] - Info['account']['init_balance'], 2)
    Info['account']['profit_rate'] = round((100 * Info['account']['profit']) / Info['account']['init_balance'], 2)

    # 计算仓位总价值和杠杆率
    Info['count']['total'] = round(Info['count']['long'] + Info['count']['short'], 2)
    Info['count']['leverage'] = round(Info['count']['total'] / Info['account']['margin_balance'], 2)


# 更新仓位信息
def UpdatePosition():
    
    # 获取永续合约的仓位信息
    pos = exchange.GetPositions(Info['base_coin'] + ".swap")
    
    # 记录仓位信息更新时间
    Info['time']['update_pos_time'] = time.time() * 1000

    # 初始化仓位信息
    position_info = {symbol: {'amount': 0, 'hold_price': 0, 'unrealised_profit': 0} for symbol in Info['trade_symbols']}

    # 遍历仓位信息,更新相应币种的仓位
    for data in pos:
        symbol = data['Symbol'].split("_")[0]
        
        # 过滤掉不符合条件的币种
        if not data['Symbol'].split(".")[0].endswith(Info['base_coin']) or symbol not in Info['trade_symbols']:
            continue
        
        # 如果仓位不为零,则需要单向持仓
        if position_info[symbol]['amount'] != 0:
            raise Exception("需要单向持仓")
        
        # 更新仓位信息
        position_info[symbol] = {
            'amount': data['Amount'] * Info['precision'][symbol]['ctVal'] if data['Type'] == 0 else -data['Amount'] * Info['precision'][symbol]['ctVal'],
            'hold_price': data['Price'],
            'unrealised_profit': data['Profit']
        }

    # 初始化仓位统计数据
    Info['count'] = {'long': 0, 'short': 0, 'total': 0, 'leverage': 0}

    # 遍历更新后的仓位信息
    for symbol, info in position_info.items():
        deal_volume = abs(info['amount'] - Info['position'][symbol]['amount'])
        direction = 1 if info['amount'] - Info['position'][symbol]['amount'] > 0 else -1
        
        # 如果仓位发生变化,记录成交信息
        if deal_volume:
            deal_price = Info['order'][symbol]['buy']['price'] if direction == 1 else Info['order'][symbol]['sell']['price']
            Log(
                symbol,
                "仓位更新:",
                round(Info['position'][symbol]['value'], 1),
                " -> ",
                round(info['amount'] * Info['ticker'][symbol]['last'], 1),
                ", 买" if direction == 1 else ", 卖",
                ", 成交价:",
                deal_price,
                ", 成本价:",
                round(Info['position'][symbol]['hold_price'], Info['precision'][symbol]['price_precision']),
            )

        # 更新仓位信息
        Info['position'][symbol]['amount'] = info['amount']
        Info['position'][symbol]['hold_price'] = info['hold_price']
        Info['position'][symbol]['value'] = round(Info['position'][symbol]['amount'] * Info['ticker'][symbol]['last'], 2)
        Info['position'][symbol]['unrealised_profit'] = info['unrealised_profit']

        # 统计多头和空头仓位价值
        if Info['position'][symbol]['amount'] > 0:
            Info['count']['long'] += abs(Info['position'][symbol]['value'])
        else:
            Info['count']['short'] += abs(Info['position'][symbol]['value'])
  1. UpdateAccount函数

    • 检查时间间隔:每次更新账户时,确保上次更新距离现在超过1分钟,避免过于频繁更新。
    • 更新账户信息:调用exchange.GetAccount获取账户信息,并计算各种账户参数,如margin_usedwallet_balanceunrealised_profit等。
    • 初始化余额:首次运行时初始化账户的初始余额,并保存在全局变量Info['account']['init_balance']中。
    • 计算利润:基于当前余额和初始余额计算利润和利润率。
  2. UpdatePosition函数

    • 获取仓位信息:调用exchange.GetPositions()获取当前的仓位状态。
    • 更新仓位:根据获取的仓位数据更新目标币种的仓位信息(如amounthold_priceunrealised_profit等)。
    • 计算杠杆率:基于当前的多头、空头仓位价值和保证金余额,计算整体杠杆率。

通过这两个函数,策略可以持续监控账户状态及仓位变化,为后续的交易决策提供实时的数据支持。

交易

根据策略逻辑执行买卖操作。可以是市价单、限价单或其他订单类型。该步骤涉及到与交易所API进行交互,发送买入或卖出的请求。成功的订单执行会影响账户的余额和持仓。

目的: - 通过API下达交易指令,完成买卖操作。 - 确保订单类型和数量符合策略要求和交易所规范。

# 订单函数
def Order(symbol, direction, price, amount, msg):
    pair = f"{symbol}_{Info['base_coin']}.swap"  # 构造交易对名称
    ret = exchange.CreateOrder(pair, direction, price, amount, msg)  # 执行下单操作
    
    # 判断是否下单成功
    if ret:
        Info['order'][symbol][direction]['id'] = ret  # 记录订单ID
        Info['order'][symbol][direction]['price'] = price  # 记录下单价格
    else:
        Log(f"{symbol} {direction} {price} {amount} 下单异常")  # 输出异常信息

# 交易函数
def Trade(symbol, direction, price, amount, msg):
    
    # 根据最小价格变动调整价格
    price = round(price - (price % Info['precision'][symbol]['tick_size']), Info['precision'][symbol]['price_precision'])
    
    # 计算调整后的交易数量
    amount = amount / Info['precision'][symbol]['ctVal']  # 计算真实合约数量
    amount = round(amount - (amount % Info['precision'][symbol]['amount_size']), Info['precision'][symbol]['amount_precision'])

    # 限制最大交易数量
    if Info['precision'][symbol]['max_qty'] > 0:
        amount = min(amount, Info['precision'][symbol]['max_qty'])
    
    new_order = False
    
    # 如果新价格与之前的订单价格差异大于0.0001,则重新下单

    if Info['order'][symbol][direction]['price'] > 0 and abs(price - Info['order'][symbol][direction]['price']) / price > 0.0001:
        Log('已持订单,订单价格发生变化')
        new_order = True
    
    # 如果交易数量为0或者当前订单ID为0,则撤单
    if amount <= 0 or Info['order'][symbol][direction]['id'] == 0:
        Log('新订单产生')
        new_order = True
    
    # 如果需要新订单
    if new_order:
        # 如果有原有订单,撤销它
        if Info['order'][symbol][direction]['id'] != 0:
            exchange.CancelOrder(Info['order'][symbol][direction]['id'])
            Info['order'][symbol][direction]['id'] = 0
            Info['order'][symbol][direction]['price'] = 0
            Log('撤单成功:', symbol)
        
        
        # 如果更新仓位或ticker的延迟太高,则不下单
        if (time.time() * 1000 - Info['time']['update_pos_time'] > 2 * Info['interval'] * 1000 or 
            time.time() * 1000 - Info['time']['update_ticker_time'] > 2 * Info['interval'] * 1000):
            Log(time.time() * 1000, Info['time']['update_pos_time'], time.time() * 1000 - Info['time']['update_pos_time'])
            Log(time.time() * 1000, Info['time']['update_ticker_time'], time.time() * 1000 - Info['time']['update_ticker_time'])
            Log('延迟过高')
            return
        
        # 如果订单金额或数量过低,不执行下单操作
        if price * amount <= Info['precision'][symbol]['min_notional'] or amount < Info['precision'][symbol]['min_qty']:
            Log(f"{symbol} 下单量太低", price * amount)
            return
        
        # 执行下单操作
        Log('order下单:', symbol)
        Order(symbol, direction, price, amount, msg)
  1. Order函数

    • 负责创建订单,成功后会记录订单ID和价格,失败则输出错误信息。
  2. Trade函数

    • 根据市场价格和数量进行调整,判断是否需要撤单并重新下单,避免订单执行错误或重复操作。
  3. CancelOrder函数

    • 为自定义的撤单操作,负责取消当前的挂单。

状态展示

实时展示策略的运行状态,包括账户余额、当前持仓、交易执行情况、当前市场价格等。这一步不仅仅是为了监控策略运行情况,也是方便策略优化和调试时快速了解策略的表现。

目的: - 及时展示策略运行的关键信息,便于用户监控。 - 提供反馈机制,显示交易执行是否成功或是否存在错误。

# 更新状态函数
def UpdateStatus():
    
    # 如果距离上次更新的时间小于4秒,则直接返回
    if time.time() * 1000 - Info['time']['update_status_time'] < 4000:
        return
    
    # 更新状态时间
    Info['time']['update_status_time'] = time.time() * 1000

    # 账户信息表格
    table1 = {
        "type": "table",
        "title": "账户信息",
        "cols": [
            "初始余额", "钱包余额", "保证金余额", "已用保证金", "可用保证金",
            "总收益", "收益率", "未实现收益", "总持仓", "已用杠杆", "循环延时"
        ],
        "rows": [
            [
                Info['account']['init_balance'],  # 初始余额
                Info['account']['wallet_balance'],  # 钱包余额
                Info['account']['margin_balance'],  # 保证金余额
                Info['account']['margin_used'],  # 已用保证金
                Info['account']['margin_free'],  # 可用保证金
                Info['account']['profit'],  # 总收益
                str(Info['account']['profit_rate']) + "%",  # 收益率
                round(Info['account']['unrealised_profit'], 2),  # 未实现收益
                round(Info['count']['total'], 2),  # 总持仓
                Info['count']['leverage'],  # 已用杠杆
                str(Info['time']['loop_delay']) + "ms",  # 循环延时
            ],
        ],
    }
    
    # 交易对信息表格
    table2 = {
        "type": "table",
        "title": "交易对信息",
        "cols": [
            "币种", "方向", "数量", "持仓价格", "持仓价值", 
            "现价", "挂单买价", "挂单卖价", "未实现盈亏"
        ],
        "rows": [],
    }

    # 遍历每个交易对,填充交易对信息
    for symbol in Info['trade_symbols']:
        table2['rows'].append([
            symbol,  # 币种
            "LONG" if Info['position'][symbol]['amount'] > 0 else "SHORT",  # 方向
            round(Info['position'][symbol]['amount'], Info['precision'][symbol]['amount_precision'] + 2),  # 数量
            round(Info['position'][symbol]['hold_price'], Info['precision'][symbol]['price_precision']),  # 持仓价格
            round(Info['position'][symbol]['value'], 2),  # 持仓价值
            round(Info['ticker'][symbol]['last'], Info['precision'][symbol]['price_precision']),  # 现价
            Info['order'][symbol]['buy']['price'],  # 挂单买价
            Info['order'][symbol]['sell']['price'],  # 挂单卖价
            round(Info['position'][symbol]['unrealised_profit'], 2),  # 未实现盈亏
        ])

    # 输出状态日志
    LogStatus(
        f"初始化时间: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(Info['time']['start_time']))}\n",
        f"`{json.dumps(table1)}`\n" + f"`{json.dumps(table2)}`\n",
        f"最后执行时间: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())}\n"
    )

    # 每10秒钟更新一次账户信息
    if time.time() * 1000 - Info['time']['update_profit_time'] > 10 * 1000:
        UpdateAccount()  # 更新账户信息
        LogProfit(round(Info['account']['profit'], 3), '&')  # 输出收益日志
        Info['time']['update_profit_time'] = time.time() * 1000  # 更新收益时间

交易逻辑

核心的交易决策部分。根据市场数据、账户信息和仓位,结合技术指标或量化模型,决定是买入、卖出、加仓或减仓。交易逻辑会根据不同的策略发生变化,比如趋势跟随策略、均值回归策略或突破策略等。

目的: - 基于市场数据和账户状况,做出智能交易决策。 - 处理各种市场情况,确保策略在不同市场环境中能合理运行。

为方便展示框架的适用性,本文中的交易策略采用了简单的逻辑。每次下单金额固定为50 USDT,交易执行时根据当前市场的买卖价格计算出相应的买入或卖出数量。该策略的执行规则非常基础,旨在展示如何将多币种合约交易策略框架应用于实盘环境。为了保证策略的简单性和可操作性,我们设定了一个停止条件:当某个交易对的总持仓价值达到2000 USDT时,停止继续下单。通过这种方式,我们可以方便地展示策略的基本结构和框架如何与交易所的市场数据进行交互。

def MakeOrder():
    
    # 遍历所有交易对
    for symbol in Info['trade_symbols']:
        
        # 获取买价(挂单买价)
        buy_price = Info['ticker'][symbol]['bid']
        
        # 计算买入数量,根据买入金额除以买价
        buy_amount = 50 / buy_price

        # 获取卖价(挂单卖价)
        sell_price = Info['ticker'][symbol]['ask']
        
        # 计算买入数量,根据买入金额除以买价
        sell_amount = 50 / sell_price

        
        # 如果当前持仓的总价值小于2000,则进行买入操作
        if Info['position'][symbol]['value'] < 2000:
            Log('进入交易')
            Log('设定价格:', Info['ticker'][symbol]['bid'])
            Trade(symbol, "buy", buy_price, buy_amount, symbol)  # 执行买入操作
        
        #if Info['position'][symbol]['value'] < 3000:
        #    Trade(symbol, "sell", sell_price, sell_amount, symbol)  # 执行买入操作

主循环

主循环是策略框架的核心部分,负责确保策略在市场中持续、稳定地运行。它会按照设定的时间间隔,定期执行各种操作,如获取最新的市场数据、更新持仓信息、执行交易决策等。通过主循环,策略可以实时响应市场变化,并确保每次执行都基于最新的市场数据。通常,主循环会在每个新的时间周期(如每分钟、每小时,或每个新K线的生成时)触发一次。

目的: - 保证策略持续、稳定地运行,实时获取市场数据并做出交易决策。 - 每次循环确保策略执行的实时性和准确性。

def OnTick():
    try:
        # 更新市场行情信息
        UpdateTicker()
        # 更新持仓信息
        UpdatePosition()
        # 执行下单操作
        MakeOrder()
        # 更新状态信息
        UpdateStatus()
    except Exception as error:
        # 记录循环中发生的错误
        Log("循环出错: " + str(error))

def main():
    LogReset(0)  
    apiBase = "https://testnet.binancefuture.com"  # 币安期货仿真交易所        
    exchange.SetBase(apiBase)  # 设置仿真交易所基站
    # 初始化信息
    exchange.IO('dual', False)  # 单向持仓
    InitInfo()
    GetPrecision()
    
    while True:  # 无限循环
        loop_start_time = time.time() * 1000  # 获取当前时间(毫秒)
        
        # 检查上次循环时间与设定的间隔时间是否已过
        if time.time() * 1000 - Info['time']['last_loop_time'] > Info['interval'] * 1000:
            OnTick()  # 调用 OnTick 函数
            
            # 更新最后一次循环时间
            Info['time']['last_loop_time'] = time.time() * 1000
            # 计算当前循环的延迟时间
            Info['time']['loop_delay'] = time.time() * 1000 - loop_start_time
        
        # 暂停5毫秒,避免过度消耗CPU资源
        Sleep(5000)

代码解释:

  1. OnTick函数:该函数是主循环中每次执行的核心任务。它负责更新市场行情、持仓信息、执行交易操作并更新策略状态。所有的交易和信息更新操作都会在此函数中完成。如果执行过程中出现错误,会被捕获并记录下来。

  2. main函数:主函数初始化相关信息,设置交易所基站并开始无限循环。在每次循环中,程序会检查是否已过设定的时间间隔。如果是,OnTick函数会被调用来执行策略。如果未到时间间隔,程序会等待并继续循环,确保策略按照预定的时间间隔执行。

  3. 延迟控制:在每次循环结束后,程序会暂停5毫秒以降低CPU的负担。这是为了避免高频率的循环导致过度消耗计算资源。

运行逻辑

  • 初始化阶段:首先设置API和其他必要的参数,然后初始化信息并获取币种精度。
  • 主循环阶段:进入一个无限循环,每次循环会检查时间间隔,确保策略执行的时间间隔符合预定设定。
  • 执行阶段:在满足时间间隔条件后,OnTick函数会被调用,执行所有的策略操作,包括市场信息更新、交易执行等。

这样设计的主循环能保证策略在实时市场条件下持续运行,并做出及时的交易决策,从而提升策略的稳定性和准确性。

总结

这个策略框架的设计重点在于模块化和可扩展性。每个步骤都有清晰的职责,保证了策略的健壮性,同时也便于未来扩展和优化。通过合理利用交易所的API函数,策略可以简化执行,并提高回测与实盘的一致性。

需要注意的是,本展示框架是以币安仿真交易所为例进行展示的,旨在提供一个基础的策略开发和运行框架。在实际操作中,需要结合具体的实盘策略逻辑进行优化,例如根据市场行情动态调整参数、优化风险控制机制、增加异常处理等。此外,由于不同交易所在API接口、交易规则、精度设置、手续费结构等方面存在差异,因此在实际应用中,还需根据目标交易所的具体要求进行细节优化和适配,以确保策略的稳定性和兼容性。建议在实盘部署前,充分测试并验证策略的可靠性和性能。

附录python多币种框架地址

相关推荐