2
Подписаться
20
Подписчики

Количественная реализация стратегии арбитража с комиссией за короткие продажи на основе валюты

Создано: 2025-01-21 17:06:52, Обновлено: 2025-02-17 11:25:01
comments   0
hits   455

Количественная реализация стратегии арбитража с комиссией за короткие продажи на основе валюты

Представьте себе, что у вас есть стратегия, которая может оставаться стабильной среди резких колебаний на рынке криптовалют и может приносить вам устойчивую положительную прибыль независимо от того, идет ли рынок на повышение или понижение. Звучит как фантастика? На самом деле это не так. Арбитражная стратегия коротких продаж валюты с единовременной комиссией — это как раз такой волшебный инструмент для зарабатывания денег, ничего не делая.

Благодаря умелому использованию уникальных свойств валютных контрактов и механизма ставки финансирования эта стратегия позволяет не только получать стабильную прибыль на бычьем рынке, но и эффективно избегать рисков на медвежьем рынке и достигать стабильной прибыли на протяжении рыночных циклов. «Защищенный от наличных денег» характер контрактов на основе монет гарантирует, что общая стоимость стратегии останется стабильной даже в случае значительных колебаний рыночных цен. Ставка финансирования, как основной механизм бессрочных контрактов, обеспечивает дополнительный источник дохода для стратегии. В этой статье мы подробно проанализируем основную логику, процесс реализации, преимущества и недостатки стратегии коротких продаж на основе монет, чтобы помочь инвесторам понять, как добиться «пассивного дохода» с помощью этой стратегии на рынке цифровых валют. Независимо от того, являетесь ли вы новичком в количественной торговле или опытным инвестором, эта стратегия заслуживает вашего глубокого понимания и опробования.

Короткие продажи на основе монет

Характеристики валютного стандарта

Единица контракта с монетной маржей измеряется в листах, а стоимость каждого листа фиксирована (например, 1 контракт BTC стоит 100 долларов США, а 10 долларов США — ETH). Эта особенность означает, что в случае кредитного плеча 1x, даже если рыночная цена сильно колеблется, теоретически не возникнет требования о внесении дополнительного обеспечения.

Анализ прибылей и убытков

Предположим, что текущая цена составляет 100 долларов США, открываются 10 коротких контрактов coin-margin, и их стоимость равна 100 долларам США, что конвертируется в 1 единицу монеты:

  1. Снижение цен

    • Цена снижается до 50 долларов США, а норма прибыли составляет: [ \text{Скорость прибыли} = \frac{100 - 50}{50} = 100% ] Количество удерживаемых монет становится равным 2, а общая стоимость остается: [ 2 \times 50 = 100 , \text{USD} ]
  2. Рост цен

    • Цена возрастает до 200 долларов США, а норма прибыли составляет: [ \text{Скорость прибыли} = \frac{100 - 200}{200} = -50% ] Количество удерживаемых монет становится равным 0,5, а общая стоимость остается: [ 0.5 \times 200 = 100 , \text{USD} ]

Таким образом, в определенной степени общая стоимость коротких продаж валюты остается стабильной, что представляет собой операцию по сохранению денежных средств. Так откуда же берется прибыль этой стратегии? Давайте введем следующую концепцию:Ставка финансирования

Ставка финансирования

В стратегии коротких продаж на основе валюты,Ставка финансированияЭто один из основных факторов доходности стратегии, а его характеристики и изменения напрямую влияют на стабильность и прибыльность стратегии. Правильно используя характеристики ставок финансирования, стратегии могут поддерживать хорошую эффективность в различных рыночных условиях, но также необходимо обращать внимание на их потенциальные ограничения.

Определение и характеристики ставки финансирования

Ставка финансирования представляет собой регулирующий механизм на рынке бессрочных контрактов, цель которого — сбалансировать затраты на удержание длинных и коротких позиций и не допустить отклонения цены бессрочного контракта от спотовой цены в течение длительного времени. На самом деле, друзья, которые изучали CFA, все еще помнят первоначальное название бессрочного контракта — своп. Идея создания механизма ставки финансирования бессрочных контрактов во многом заимствована из процентного свопа в традиционных финансах. При процентном свопе две стороны обмениваются процентными платежами через регулярные промежутки времени на основе согласованной процентной ставки (например, фиксированная ставка против плавающей ставки) для хеджирования риска колебаний процентных ставок. Аналогичным образом, механизм ставки финансирования бессрочных контрактов также уравновешивает издержки удержания длинных и коротких позиций за счет регулярной уплаты или сбора комиссий, гарантируя, что разрыв между ценой контракта и спотовой ценой не будет слишком большим.

Количественная реализация стратегии арбитража с комиссией за короткие продажи на основе валюты

Введение ставки финансирования по сути призвано решить базовую проблему между бессрочными контрактами и спотовыми ценами. Когда цена бессрочного контракта выше спотовой цены, ставка финансирования положительная, и держатели длинных позиций платят комиссию держателям коротких позиций; когда цена бессрочного контракта ниже спотовой цены, ставка финансирования отрицательная, и держатели коротких позиций платят комиссию держателям коротких позиций. Этот механизм не только опирается на базовую концепцию процентных свопов, но и объединяет характеристики рынка цифровых валют, формируя уникальный инструмент регулирования рынка. В области цифровой валюты ее основными особенностями являются:

  1. Спрос и предложение на рынке определяют:Ставка финансирования определяется соотношением спроса и предложения между длинными и короткими позициями на рынке и является результатом игры между длинными и короткими силами.
  2. Периодический платеж:Ставка финансирования выплачивается в определенный период (например, 8 часов), а сборы переносятся между длинными и короткими позициями.
  3. Эмоциональное отражение:Положительная ставка финансирования обычно указывает на то, что рыночные настроения оптимистичны, а цена бессрочного контракта выше спотовой цены; отрицательная ставка финансирования обычно указывает на то, что рыночные настроения оптимистичны, а цена бессрочного контракта ниже спотовой цены.

Положительная ставка финансирования (ставка финансирования > 0)

  • Производительность: В условиях положительной ставки финансирования держателям длинных позиций приходится платить комиссию держателям коротких позиций.
  • Логика доходов:Благодаря стабильной выплате ставки финансирования стратегия продолжает взимать комиссию за финансирование, удерживая короткие позиции, и даже если рыночная цена вырастет, это не окажет существенного негативного влияния на доходность. Например, если ставка финансирования составляет 0,02%/8 часов, то владение контрактом стоимостью 10 000 долларов принесет следующую ежедневную доходность: [ Дневной доход = 10 000 \times 0,02% \times 3 = 6 , \text{USDT} ] Этот источник дохода относительно стабилен и менее коррелирует с колебаниями цен.

Отрицательная ставка финансирования (ставка финансирования < 0)

  • Производительность:Когда ставка финансирования отрицательная, короткие позиции должны платить комиссии за длинные позиции, а доходность стратегии может сократиться или даже привести к убыткам.
  • Точки риска:Когда отрицательные ставки финансирования сохраняются в течение длительного времени или сильно колеблются, например, на затяжном медвежьем рынке, стратегия может повлечь за собой более высокие издержки из-за уплаты комиссий за финансирование, в результате чего общая прибыль не сможет покрыть операционные расходы.

Стратегические источники прибыли

Как сказал Мастер Зинан, на начальном этапе построения стратегии необходимо понимать источники доходности и риски стратегии. Исходя из вышеизложенного, мы понимаем, что общая стоимость коротких продаж в валютном стандарте должна оставаться стабильной, поэтому источником дохода является арбитраж ставки финансирования. Некоторые студенты могут заинтересоваться, продолжит ли ставка финансирования приносить стабильную положительную прибыль? Мы проводим работы по анализу данных на международной станции DATADATA:

SELECT 
    Exchange,
    Symbol,
    toDateTime(Time / 1000) AS Time,  -- 将毫秒时间戳转换为时间戳
    Rate,
    SUM(Rate) OVER (PARTITION BY Exchange, Symbol ORDER BY Time) AS CumulativeRate  -- 计算累加的 Rate
FROM 
    klines.funding
WHERE 
    Exchange = '{{exchange}}' 
    AND Symbol = '{{symbol}}'
ORDER BY 
    Time;

Динамические параметры используют биржу Binance, а контракт выбирает стандартный контракт Bitcoin (btc_usd) для отображения совокупной ставки финансирования. Видно, что с 2020 года по настоящее время доходность ставки фондирования демонстрирует устойчиво растущий уровень, а совокупная пятилетняя доходность достигает 50%. Хотя она не может сравниться с прибылью сотен или тысяч, она относительно стабильна, поэтому мы можем разобраться в источниках прибыли этой стратегии.

В стратегии коротких продаж на основе монет ставка финансирования является ключевым источником прибыли. Поскольку единицы контрактов с маржинальной торговлей фиксированы, даже если рыночные цены колеблются, изменения стоимости контракта для коротких продавцов обычно поддаются контролю, поэтому ставка финансирования становится основным источником прибыли для стратегии. Ниже приведены конкретные эффекты ставок финансирования на стратегии:

  1. Фаза бычьего рынка (ставка финансирования положительная)

    • Феномен рынка: На бычьем рынке из-за высоких рыночных настроений инвесторы, как правило, склонны открывать длинные позиции, что приводит к увеличению длинных позиций и, таким образом, повышению ставки финансирования до положительного значения.
    • Логика доходов: В этом случае короткие продавцы получат выгоду от ставки финансирования, выплачиваемой длинными продавцами, что станет основным источником прибыли для стратегии. Поскольку ставка финансирования положительная, короткие позиции могут продолжать приносить прибыль, а используя полученную ставку финансирования, вы можете продолжать открывать короткие позиции и получать больше выгод от ставки финансирования.
    • Конкретное воздействие: Если ставка финансирования положительная и стабильная, короткие позиции будут регулярно получать ставку финансирования и не будут сильно зависеть от колебаний цен. Даже если рыночная цена вырастет, короткие продавцы могут столкнуться с большими явными убытками по контракту, но в целом чистая стоимость средств остается относительно стабильной. Это связано с тем, что источник прибыли стратегии в основном зависит от сбора ставок финансирования, а не от колебаний цен. Хотя колебания цен могут повлиять на видимую потерю контракта, поскольку изменения стоимости контракта короткой позиции поддаются контролю, основная прибыль фондов по-прежнему формируется за счет регулярного сбора ставок финансирования, а не колебаний рыночных цен. Это позволяет стратегии в определенной степени компенсировать риск колебаний цен и поддерживать стабильный рост стоимости средств.
  2. Фаза медвежьего рынка (отрицательная ставка финансирования)

    • Феномен рынка: На медвежьем рынке рыночные цены быстро падают, а короткие позиции обычно резко растут, в результате чего ставка финансирования становится отрицательной, а это означает, что держателям коротких позиций приходится платить за длинные. Однако из-за бурно развивающегося рынка цифровых валют в последние годы фазы медвежьего рынка встречаются сравнительно редко.
    • Логика доходов: Несмотря на то, что ставка финансирования отрицательная и держателям коротких позиций необходимо платить комиссию, хеджинговые характеристики стратегии по-прежнему актуальны, поскольку единица короткого контракта фиксирована, а стоимость контракта короткой позиции меняется мало. Резкие колебания цен не приведут к большим потерям. В то же время бремя ставок фондирования относительно контролируемо, и стратегия все еще может оставаться стабильной в определенной степени.

Анализируя эти две рыночные среды, можно увидеть, что прибыльность и риск стратегии коротких продаж на основе валюты в основном зависят от ставки фондирования. Когда ставка финансирования положительна на бычьем рынке, короткие продавцы могут извлечь из этого выгоду; в то время как на медвежьем рынке, несмотря на то, что ставка финансирования отрицательна, стратегия все еще имеет сильную способность сохранять стоимость, поскольку изменения стоимости контракта поддаются контролю.

Архитектура логики политики

Надежная структура стратегии является ключом к успешной реализации стратегии. Она обеспечивает четкую структуру исполнения, чтобы гарантировать, что стратегия может работать стабильно в различных рыночных условиях и эффективно справляться с рисками и волатильностью. Здесь мы ссылаемся на структуру стратегии мультивалютных контрактов на основе U компании Xiaocao Dashen и вносим определенные изменения и улучшения в валютный стандарт.

'''backtest
start: 2024-11-20 00:00:00
end: 2024-11-20 01:00:00
period: 1d
basePeriod: 1m
exchanges: [{"eid":"Futures_OKX","currency":"BTC_USD"}]
'''

import time
import json 

# 全局变量,储存数据
SYMBOLS = 'BTC'     # SYMBOLS代表要交易的币种,格式如"BTC,ETH,LTC"
QUOTO = 'USD'       # QUOTO为基础货币, 币本位为USD
INTERVAL = 5        # INTERVAL代表循环的间隔
ICEMONEY = 2000     # 冰山下单金额
ROLLINGNUM = 1      # 滚动盈利加仓数量


Info = {
    'trade_symbols': SYMBOLS.split(','),  # 交易币种
    'base_coin': QUOTO,                   # 基础货币
    'ticker': {},                         # 行情数据
    'order': {},                          # 订单信息
    'account': {},                        # 账户信息
    'precision': {},                      # 精度信息
    'position': {},                       # 仓位信息
    'time': {},                           # 时间相关数据
    'count': {},                          # 计数器
    'interval': INTERVAL                  # 循环的间隔时间
}

# 初始化策略
def InitInfo():

    # 初始化时间数据,控制更新的时间
    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['account'][symbol] = {
            'init_balance': 0,  # 初始余额
            'margin_balance': 0,  # 保证金余额
            'margin_used': 0,  # 已用保证金
            'margin_free': 0,  # 可用保证金
            'profit': 0,  # 总收益
            'profit_rate': 0,  # 收益率
            'unrealised_profit': 0,  # 未实现收益
        } # 初始化账户信息,初始余额为0

        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
        }

# 获取精度信息
def GetPrecision():
    # 获取交易所的市场信息

    # 回测系统需要获取行情信息后, 才能获取市场信息,实盘系统可忽略
    for symbol in Info['trade_symbols']:
         curcontract = symbol + '_' + QUOTO + '.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张代表100USD
            }

            Log(f"初始化币种信息: {symbol}, "
                 f"价格精度: {Info['precision'][symbol]['tick_size']}, "
                 f"数量精度: {Info['precision'][symbol]['amount_size']}, "
                 f"价格小数位精度: {Info['precision'][symbol]['price_precision']}, "
                 f"数量小数位精度: {Info['precision'][symbol]['amount_precision']}, "
                 f"最小下单数量: {Info['precision'][symbol]['min_qty']}, "
                 f"最大下单数量: {Info['precision'][symbol]['max_qty']}, "
                 f"最小交易额: {Info['precision'][symbol]['min_notional']}, "
                 f"合约价值(张): {Info['precision'][symbol]['ctVal']}")


# 更新行情信息
def UpdateTicker():
    
    # 记录当前更新时间戳
    Info['time']['update_ticker_time'] = time.time() * 1000 # 使用time.time()获取当前时间的时间戳
    
    # 遍历获取到的行情数据
    for symbol in Info['trade_symbols']:
        
        curcontract = symbol + '_' + QUOTO + '.swap'
        data = exchange.GetTicker(curcontract)
        
        if not data:
            Log("获取行情失败", GetLastError())
            return
        
        # 更新行情的卖出价、买入价和最后成交价
        Info['ticker'][symbol]['ask'] = float(data['Sell'])  # 卖出价
        Info['ticker'][symbol]['bid'] = float(data['Buy'])   # 买入价
        Info['ticker'][symbol]['last'] = float(data['Last']) # 最后成交价


# 更新账户信息
def UpdateAccount():
    # 遍历所有交易币种,更新账户信息
    for symbol in Info['trade_symbols']:    
        curcontract = symbol + '_' + QUOTO  # 拼接币种和报价货币,形成合约标识
        exchange.SetCurrency(curcontract)  # 设置当前合约
        
        # 获取账户信息
        account = exchange.GetAccount()
        
        # 如果账户信息获取失败,记录日志并结束函数
        if account is None:
            Log(curcontract, ": 更新账户失败")
            return
        
        # 计算账户的关键信息
        # 'Stocks': 可用余额, 'FrozenStocks': 冻结余额, 'Equity': 总权益, 'UPnL': 未实现盈亏, 区别U本位(Balance)
        Info['account'][symbol]['margin_used'] = account['Equity'] - account['Stocks']  # 已用保证金
        Info['account'][symbol]['margin_balance'] = account['Equity']  # 当前账户总权益
        Info['account'][symbol]['margin_free'] = account['Stocks']  # 当前可用余额
        Info['account'][symbol]['unrealised_profit'] = account['UPnL']  # 未实现盈亏

        # 从全局存储中读取账户初始余额字典
        accDict = _G("init_balance")
        if accDict is None:
            accDict = {}  # 如果全局存储为空,则初始化为空字典

        # 初始化账户初始余额(仅在第一次运行时设置)
        if not Info['account'][symbol]['init_balance']:
            # 如果全局存储有记录且余额大于0,则使用该记录作为初始余额
            if accDict and accDict.get(symbol) and accDict[symbol] > 0:
                Info['account'][symbol]['init_balance'] = round(accDict[symbol], 2)
            else:
                # 否则,将当前保证金余额作为初始余额
                Info['account'][symbol]['init_balance'] = Info['account'][symbol]['margin_balance'] * Info['ticker'][symbol]['last']
                accDict[symbol] = Info['account'][symbol]['init_balance']  # 更新全局存储
                _G("init_balance", accDict)

        # 计算账户利润及利润率
        Info['account'][symbol]['profit'] = round(Info['account'][symbol]['margin_balance'] * Info['ticker'][symbol]['last'] - Info['account'][symbol]['init_balance'], 2)  # 当前利润
        Info['account'][symbol]['profit_rate'] = round((100 * Info['account'][symbol]['profit']) / Info['account'][symbol]['init_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)的一部分作为标识
        symbol = data['Symbol'].split("_")[0]
        
        # 过滤掉不属于指定基准币种或不在交易列表中的币种
        if not data['Symbol'].split(".")[0].endswith(Info['base_coin']) or symbol not in Info['trade_symbols']:
            continue
        
        # 更新仓位信息,区分多头和空头(通过 Type 字段)
        position_info[symbol] = {
            'amount': data['Amount'] if data['Type'] == 0 else -data['Amount'],  # 多头为正,空头为负
            'hold_price': data['Price'],  # 仓位持有价格
            'unrealised_profit': data['Profit']  # 未实现盈亏
        }

    # 初始化每个币种的仓位统计数据
    # long: 多头价值, short: 空头价值, total: 总仓位价值, leverage: 杠杆率
    for symbol in Info['trade_symbols']:
        Info['count'][symbol] = {'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]['amount'], 1),
                " -> ",
                round(info['amount'], 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['precision'][symbol]['ctVal'], 2)  # 仓位价值
        Info['position'][symbol]['unrealised_profit'] = info['unrealised_profit']  # 更新未实现盈亏

        # 统计多头和空头仓位价值
        if Info['position'][symbol]['amount'] > 0:
            # 如果为多头,增加多头仓位价值
            Info['count'][symbol]['long'] += abs(Info['position'][symbol]['value'])
        else:
            # 如果为空头,增加空头仓位价值
            Info['count'][symbol]['short'] += abs(Info['position'][symbol]['value'])

        # 计算仓位总价值(按最新价格计算)
        Info['count'][symbol]['total'] = round((Info['count'][symbol]['long'] + Info['count'][symbol]['short']) / Info['ticker'][symbol]['last'], 2)
        # 计算杠杆率(总仓位价值与账户保证金的比值)
        Info['count'][symbol]['leverage'] = round(Info['count'][symbol]['total'] / Info['account'][symbol]['margin_balance'], 2)

# 订单函数
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  # 记录下单价格
        Log('记录下单价格:', price, direction, Info['order'][symbol][direction]['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('Ticker更新时间', 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)


# 更新状态函数
def UpdateStatus():
    
    # 更新状态时间
    Info['time']['update_status_time'] = time.time() * 1000

    # 账户信息表格
    table1 = {
        "type": "table",
        "title": "账户信息",
        "cols": [
            "币种", "初始权益", "实时权益", "可用余额", 
            "总收益", "收益率"
        ],
        "rows": [],
    }

    # 遍历每个交易对,填充交易对信息
    for symbol in Info['trade_symbols']:
        table1['rows'].append([
            symbol,  # 币种
            round(Info['account'][symbol]['init_balance'], 2),  # 初始权益
            round(Info['account'][symbol]['margin_balance'] *  Info['ticker'][symbol]['last'], 2),  # 实时权益
            round(Info['account'][symbol]['margin_free'] *  Info['ticker'][symbol]['last'], 2), # 可用余额
            round(Info['account'][symbol]['profit'], 2),  # 总收益
            str(Info['account'][symbol]['profit_rate']) + "%"  # 收益率
        ])

    # 交易对信息表格
    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",  # 方向
            Info['position'][symbol]['amount'],  # 数量
            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'])  # 现价
        ])

    # 输出状态日志
    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"循环延时: {str(Info['time']['loop_delay']) + 'ms'}\n",
        f"最后执行时间: {_D()}\n"
    )

    totalprofit = 0
    for symbol in Info['trade_symbols']:
        totalprofit += Info['account'][symbol]['profit']  

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


def MakeOrder():
    
    # 遍历所有交易对
    for symbol in Info['trade_symbols']:
        
        availBal = Info['account'][symbol]['margin_free'] *  Info['ticker'][symbol]['last'] #可用金额
        sell_price = Info['ticker'][symbol]['ask'] #卖出价格

        if availBal > ICEMONEY: #可用金额大于冰山挂单数量,起始建仓
            Trade(symbol, "sell", sell_price, ICEMONEY, symbol)  # 执行买入操作
        elif availBal > ROLLINGNUM * Info['precision'][symbol]['ctVal']: #可用盈利大于滚动加仓数量,逐步下单
            Trade(symbol, "sell", sell_price, ROLLINGNUM * Info['precision'][symbol]['ctVal'], symbol)  # 执行买入操作

def OnTick():
         
    # 更新市场行情信息
    UpdateTicker()

    # 更新账户信息
    UpdateAccount()
     
    # 更新持仓信息
    UpdatePosition()

    # 执行下单操作
    MakeOrder()
    
    # 更新状态信息
    UpdateStatus()

def main():

    LogReset(0)                # 日志重置
    Log('策略起始#0000ff')
    # 初始化信息
    InitInfo()                 # 初始化币种信息
    GetPrecision()             # 获取精度信息
    exchange.SetMarginLevel(1) # 设置杠杆倍数
    
    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(5)

1. Глобальные переменные и описание функций

Стратегия основана на простых определениях переменных и реализует скользящие добавления позиций и мониторинг состояния с помощью модульных функций.

  • SYMBOLS: Торговая валюта (например, «BTC»).
  • QUOTO:Базовая валюта, валютный стандарт обычно — доллар США.
  • INTERVAL: Временной интервал между циклами политики.
  • ICEMONEY: Первоначальная сумма заказа, используется для айсберг-заказов.
  • ROLLINGNUM: Количество позиций, добавленных после получения прибыли.

2. Основные функциональные модули

Ниже приводится краткое описание каждого функционального модуля:

  1. Функция инициализации (InitInfo)
    Используется для загрузки информации о валюте транзакции и начальном состоянии счета.

  2. Получить точную информацию (GetPrecision)
    Получите минимальный размер ордера и стоимость контракта для каждой торговой пары через API биржи.

  3. ОбновлениеTicker
    Регулярно получайте актуальную рыночную информацию, включая лучшую цену спроса, лучшую цену предложения и последнюю цену.

  4. Обновления аккаунта и позиции (UpdateAccount, UpdatePosition)
    Синхронизация остатков на счетах и ​​информации о позициях в режиме реального времени служит основой для принятия торговых решений.

  5. Торговля и управление заказами (заказ, торговля)
    Унифицированные функции размещения и исполнения ордеров, поддерживающие лимитные ордера и рыночные ордера.

  6. Мониторинг статуса (UpdateStatus)
    Отслеживайте статус стратегии, включая текущую прибыль и убытки, а также невыполненные заказы.

3. Логика стратегического заказа (MakeOrder)

Суть стратегии заключается в следующем:Исходное положение(Положение айсберга) иПоложение прокатки(Управляется параметром положения прокатки ROLLINGNUM). Ниже приводится подробное описание конкретной логики:

  1. Проверка исходного положения:Проверьте, превышает ли остаток на счете первоначальную сумму открытия айсберга (ICEMONEY). При соблюдении условий позиции будут открываться постепенно партиями, чтобы уменьшить чрезмерное проскальзывание цен, вызванное открытием позиции за один раз.
  2. Стратегия скользящей позиции:В соответствии с прибыльностью счета (доходом от ставки финансирования) разумно увеличивайте позицию, оптимизируйте доход за счет увеличения скользящей позиции, чтобы повысить общую прибыльность стратегии.

Количественная реализация стратегии арбитража с комиссией за короткие продажи на основе валюты

По результатам бэктестинга стратегии мы видим, что стратегия достигла стабильной доходности в нескольких рыночных циклах, особенно на бычьем рынке, где ставка фондирования была положительной в течение длительного времени. Поэтому эта стратегия в определенной степени очень подходит для управления крупными фондами. Такие характеристики, как низкая волатильность и стабильная доходность, могут удовлетворить двойную потребность крупных фондов в контроле рисков и стабильной доходности. В то же время стратегия использует кредитное плечо 1x, что позволяет избежать риска ликвидации, вызванного высоким кредитным плечом, и дополнительно повышает ее безопасность.

Анализ преимуществ и недостатков стратегии

преимущество

  1. Стратегия проста и легка в реализации.
    Логика понятна и не требует сложных расчетов, что делает ее подходящей для управления крупными фондами со стороны хедж-фондов или индивидуальных инвесторов.

  2. Сильное сопротивление риску
    Кредитное плечо 1x позволяет избежать риска ликвидации, а валютные характеристики гарантируют, что стоимость доллара США останется постоянной, независимо от значительных колебаний рынка.

  3. Стабильный доход
    На бычьем рынке ставка финансирования выше и имеет сильную масштабируемость, а полученные валюты можно использовать для других инвестиций (например, для стейкинга).

недостаток

  1. Сильная зависимость от валюты и рыночных условий
    Это недостаток. Когда ставка финансирования валюты положительна в течение длительного времени (шорты платят лонгам), например, контракты BNB, используйте DATADATA для выбора контрактов на основе монет BNB. Вы можете видеть, что из-за настроек биржи ставка финансирования накапливается до отрицательного значения. Кроме того, когда большой цикл приходится на долгосрочный медвежий рынок (2022 г.), а ставка финансирования отрицательная, доходность может не покрыть расходы на реализацию стратегии.

  1. Отсутствие жесткости стратегии
    Текущая стратегия не включает в себя динамическую логику корректировки, такую ​​как отсутствие мер р�