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

Золотая лихорадка на платформе Inventor: практический анализ высокогибкой платформы трендовой торговли на Python

Создано: 2025-08-22 17:25:52, Обновлено: 2025-08-26 09:56:27
comments   0
hits   468

Я часто захожу на платформу Inventor и всегда нахожу сокровища. Сегодня я нашёл 21-летнего парня.Стратегия трендаЯ восхищаюсь изысканной и совершенной структурой кода автора оригинала, которая отличается высокой гибкостью. Оригинальная стратегия — это JS-версия, переписанная для удобства пользователей Python.

Честно говоря, многие новички, впервые приступая к количественной торговле, совершают множество ошибок. Они часто сталкиваются с такими проблемами, как невыполненные ордера, убытки из-за плохого управления рисками и потеря данных после перезапуска стратегии. Позже я постепенно осознал важность хорошей платформы, которая может помочь нам избежать многих ловушек. Эта платформа трендовой стратегии — невероятно ценный инструмент. Это больше, чем просто торговая стратегия; это, скорее, набор инструментов, предоставляющий вам базовые, но важные функции, такие как размещение ордеров, стоп-лосс ордера и управление данными. Вам нужно сосредоточиться только на ключевых вопросах: «когда покупать» и «когда продавать». Более того, платформа очень свободна в использовании, позволяя легко заменить EMA на MACD, RSI или любой другой индикатор по вашему выбору. Хотите следовать за трендами? Без проблем. Хотите попробовать возврат к среднему? Или хотите объединить несколько индикаторов? Конечно. Такая гибкость невероятно полезна: вы можете модифицировать один и тот же код, экспериментируя с разными идеями.

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

Структура и функция фреймворка

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

Инициализация и настройка

функция init

  • Функции__init__Эта функция представляет собой метод инициализации класса стратегии, отвечающий за настройку базовой конфигурации стратегии, инициализацию переменных и получение рыночной информации. Эта функция обеспечивает настройку необходимых параметров перед запуском стратегии, обеспечивая бесперебойное выполнение последующих торговых операций.
  • Шаги
    1. Базовая конфигурация: Установите торговую валюту, тип контракта, правила тейк-профита и стоп-лосса и т. д.
    2. Информация о рынке:Убедитесь в точности цен и количества, указанных в контракте, чтобы убедиться в законности заказа.
    3. Инициализация переменных: Включая оценку тренда, параметры стоп-профита и стоп-лосса, статистические переменные и т. д., помогающие стратегиям принимать решения на основе рыночных условий.
    4. Настройки обмена:Настройте API-интерфейс биржи в соответствии с рыночной информацией, например, установив маржу, точность и т. д.

функция initDatas

  • Функции: Инициализирует данные при запуске стратегии, включая активы счета, статистику прибыли и т. д.
  • Шаги
    1. Экономьте время выполнения политики.
    2. Чтение локальных данных пользователя.
    3. Инициализируйте активы счета, статистику доходов и другие данные.
    4. Проверяет, включены ли тейк-профит и обратный тейк-профит одновременно.

Управление данными и хранение

Функция saveStrategyRunTime

  • Функции: Сохраните время начала действия политики для последующей статистики и мониторинга.
  • Шаги
    1. Проверьте, сохранено ли локально время выполнения.
    2. Если текущее время не сохранено, запишите его и сохраните локально.
    3. Если оно было сохранено, прочтите локально сохраненное время.

функция setStrategyRunTime

  • Функции: Установите время начала действия политики и сохраните его в локальном хранилище.
  • Шаги
    1. Использование платформы_GФункция сохраняет переданную метку времени локально.
    2. Обновите время начала выполнения в данных политики.

Функция getDaysFromTimeStamp

  • Функции: вычисляет разницу в днях между двумя временными метками для расчета продолжительности выполнения политики.
  • Шаги
    1. Проверяет, является ли время окончания более ранним, чем время начала, и возвращает 0, если это так.
    2. Рассчитывает разницу в секундах между двумя временными метками и преобразует ее в дни.
    3. Возвращает разницу в днях.

Функция saveUserDatasLocal

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

функция readUserDataLocal

  • Функции: Чтение локально сохраненных данных пользователя для восстановления данных при перезапуске политики.
  • Шаги
    1. Проверьте, сохранены ли локально какие-либо данные.
    2. Если нет, инициализируйте данные и сохраните их локально.
    3. Если да, то он считывается и загружается в политику.

функция clearUserDataLocal

  • Функции: Очистка локально сохраненных пользовательских данных, обычно используемых для сброса политики или отладки.
  • Шаги
    1. Использование платформы_GФункция очищает локальные данные.
    2. Операции по расчистке бревен.

Взаимодействие политик и обработка команд

Функция runCmd

  • Функции: Обрабатывает команды, отправленные пользователями через интерактивный интерфейс, такие как очистка локальных данных, изменение количества заказа и т. д.
  • Шаги
    1. Получите команду, отправленную пользователем.
    2. Выполнять соответствующие операции в зависимости от типа команды, например, очистка локальных данных, изменение количества заказа и т. д.
    3. Запишите результаты выполнения команды.

Торговля и управление заказами

функция orderDirectly

  • Функции: размещайте заказы напрямую на основе направления и цены, поддерживая операции открытия и закрытия.
  • Шаги
    1. Выберите торговую функцию в зависимости от направления (покупка или продажа).
    2. Установите направление торговли.
    3. Выполнить операцию заказа и вернуть результат.

функция openLong

  • Функции: Откройте длинную позицию и разместите ордер на основе цены и количества.
  • Шаги
    1. Рассчитайте фактическое количество заказа.
    2. ВызовorderDirectlyФункция выполняет операцию покупки.

функция openShort

  • Функции:Откройте короткую позицию и разместите ордер на основе цены и количества.
  • Шаги
    1. Рассчитайте фактическое количество заказа.
    2. ВызовorderDirectlyФункция выполняет операцию продажи.

Функция coverLong

  • Функции:Закрывайте длинные позиции и размещайте ордера на основе цены и количества.
  • Шаги
    1. ВызовorderDirectlyФункция выполняет операцию продажи.

функция coverShort

  • Функции:Закрыть короткую позицию и разместить ордер на основе цены и количества.
  • Шаги
    1. ВызовorderDirectlyФункция выполняет операцию покупки.

функция getRealOrderSize

  • Функции: Пересчитывает фактическое количество заказа на основе цены и количества, а также поддерживает размещение заказов на основе коэффициента маржи.
  • Шаги
    1. Рассчитайте фактический объем заказа на основе того, размещен ли заказ в соответствии с коэффициентом маржи.
    2. Возвращает рассчитанное количество заказа.

Управление рисками и статистика доходности

Функция getSinglePositionMargin

  • Функции: Рассчитайте маржу, занимаемую одной позицией.
  • Шаги
    1. Маржа рассчитывается на основе направления и количества позиции.
    2. Возвращает результат расчета.

Функция getSinglePositionProfit

  • Функции: Рассчитайте доходность и прибыльность одной позиции.
  • Шаги
    1. Рассчитать прибыль на основе направления позиции и текущей цены.
    2. Возвращает прибыль и доходность.

Функция calculateForcedPrice

  • Функции: Рассчитывает цену ликвидации позиции.
  • Шаги
    1. Цена ликвидации рассчитывается на основе направления позиции и остатка на счете.
    2. Возвращает результат расчета.

функция getMaxOrderSize

  • Функции: Рассчитайте максимальный объем заказа.
  • Шаги
    1. Максимальный объем ордера, который можно разместить, рассчитывается на основе баланса счета и кредитного плеча.
    2. Возвращает результат расчета.

Функция getAccountAsset

  • Функции: Рассчитывает общие активы счета, включая позиции и доступный остаток.
  • Шаги
    1. Рассчитайте общий капитал на основе позиций и остатка на счете.
    2. Возвращает результат расчета.

Функция calculateProfit

  • Функции: Рассчитайте и запишите доходность стратегии.
  • Шаги
    1. Рассчитайте разницу между текущей совокупной доходностью и первоначальными активами.
    2. Запишите результаты и обновите статистические переменные.
    3. Сохраняйте данные о доходах локально.

функция isEnoughAssetToOrder

  • Функции: Проверьте, достаточно ли средств на счете для оформления заказа.
  • Шаги
    1. Получите информацию о балансе счета.
    2. Рассчитайте необходимые средства на основе типа валюты транзакции (на основе USDT или монет).
    3. Проверьте, соответствует ли баланс счета требованиям заказа.
    4. Возвращает логическое значение, указывающее, достаточно ли средств.

Оценка тренда и торговая логика

функция runInKLinePeriod

  • Функции:Определите, следует ли выполнять логику стратегии на основе цикла K-линии.
  • Шаги
    1. Проверьте, обработана ли текущая К-линия.
    2. Если не обработано, отметьте как обработанное и вернитеTrueВ противном случае вернитеFalse

Функция trendJudgment (модуль оценки основного тренда)

  • Функции: Определение текущего тренда на основе технических индикаторов. Это самый гибкий модуль во всей системе. Пользователи могут заменять различные технические индикаторы для определения тренда в соответствии со своими потребностями.
  • Текущая реализация: Используйте EMA (экспоненциальную скользящую среднюю) в сочетании со стандартным отклонением для определения тренда.
  • Масштабируемость:Эта функция разработана как подключаемый модуль, и пользователи могут легко заменить его другими техническими индикаторами, такими как:
    • RSI (индекс относительной силы):Оценка условий перекупленности и перепроданности
    • MACD (схождение-расхождение скользящих средних): Определите поворотные моменты тренда
    • Полосы Боллинджера:Оценка тренда на основе волатильности цен
    • Индикатор KDJ:Комбинированная оценка импульса и тренда
    • Многоуровневые портфели: Несколько индикаторов можно комбинировать для более точной оценки тренда.
  • Шаги
    1. Рассчитайте индикатор EMA и определите, пересекает ли его цена.
    2. Определите, находится ли показатель в тренде, на основе стандартного отклонения.
    3. Возвращает текущий тренд (длинный, короткий или диапазон).

функция стоп-лосса

  • Функции:Выполнить операцию стоп-лосса в соответствии с правилами стоп-лосса.
  • Шаги
    1. Проверьте, достигает ли позиция условий стоп-лосса.
    2. Если он достигнут, позиция будет закрыта и будет записана информация о стоп-лоссе.

функция takeProfit

  • Функции:Выполнить операцию тейк-профита в соответствии с правилами тейк-профита.
  • Шаги
    1. Проверьте, соответствует ли позиция условиям тейк-профита.
    2. Если он достигнут, позиция будет закрыта и будет зафиксирована информация о тейк-профите.

Функция отслеживанияTakeProfit

  • Функции: Выполнить операцию тейк-профита в соответствии с правилами обратного вызова тейк-профита.
  • Шаги
    1. Проверьте, соответствует ли позиция условиям срабатывания обратного тейк-профита.
    2. Если он достигнут, позиция будет закрыта и будет зафиксирована информация о тейк-профите.

функция заказа

  • Функции: Выполнение ордерной операции на основе результатов оценки тренда.
  • Шаги
    1. Проверьте текущие позиции.
    2. Открывать или закрывать позиции на основе результатов оценки тренда.

Основная логика стратегии

Функция trendStrategy

  • Функции: Основная логическая функция стратегии, отвечающая за выполнение оценки тренда, стоп-лосс и тейк-профит, обратный тейк-профит и операции с ордерами.
  • Шаги
    1. Получить рыночные данные: Получите актуальную информацию о рынке, информацию о позициях, информацию о счете и данные K-line.
    2. Проверить позиции: Убедитесь, что ни длинные, ни короткие позиции не удерживаются одновременно, в противном случае будет выдано исключение.
    3. Стратегическое взаимодействие: Обрабатывает команды, отправленные пользователями через интерактивный интерфейс.
    4. Печать информации в строке состояния: Обновление и печать статуса стратегической операции, информации о счете и статуса позиции.
    5. Остановка убытков:Проверка и выполнение операций стоп-лосса в соответствии с правилами стоп-лосса.
    6. Задержка: Проверка и выполнение операций по фиксации прибыли в соответствии с правилами фиксации прибыли.
    7. Тейк-профит по обратному вызову: Проверка и выполнение операций по получению прибыли в соответствии с правилами обратного вызова по получению прибыли.
    8. Проверка цикла K-линии: Убедитесь, что логика стратегии выполняется в соответствии с циклом K-линии.
    9. Оценка тенденций: Определите текущий тренд (длинный, короткий или колебательный) на основе технических индикаторов.
    10. Оформить заказ: Открыть или закрыть позицию на основе результатов оценки тренда.

Мониторинг состояния и вывод журнала

функция printLogStatus

  • Функции: Печать статуса операции стратегии, информации о счете и статуса позиции.
  • Шаги
    1. Создайте табличные данные обзора стратегии, средств на счетах и ​​позиций.
    2. использоватьLogStatusФункция выводит данные таблицы в строку состояния.

Основная функция и реализация стратегии

основная функция

  • Функции: Основная функция стратегии, отвечающая за инициализацию стратегии и выполнение цикла логики стратегии.
  • Шаги
    1. Инициализируйте среду моделирования обмена.
    2. Создайте экземпляр стратегии и инициализируйте данные.
    3. Логика стратегии реализуется циклично, проверяя рыночную ситуацию и совершая торговые операции через регулярные промежутки времени.

Особенности фреймворка

  1. Гибкое суждение о тренде: Используя экспоненциальную скользящую среднюю (EMA) и стандартное отклонение, эта стратегия позволяет гибко определять рыночные тренды и применима к различным рыночным условиям. Эта функция приведена лишь в качестве примера; пользователи могут использовать различные технические индикаторы (такие как RSI, MACD, полосы Боллинджера и т. д.) для определения трендов по мере необходимости.
  2. Различные механизмы стоп-лосса и тейк-профита:Поддерживает фиксированный процентный стоп-лосс, тейк-профит и обратный тейк-профит для удовлетворения потребностей трейдеров с различными предпочтениями в отношении риска.
  3. Локальное управление данными: Данные о работе политики и данные пользователей сохраняются локально, чтобы гарантировать возможность восстановления политики в предыдущее состояние после перезапуска.
  4. Интерактивные команды: Поддерживает взаимодействие с политиками через командную строку, что упрощает для пользователей настройку параметров политики или выполнение определенных операций.

Применимость

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

  1. Поддержка спотового рынка: В настоящее время эта структура в основном ориентирована на контрактный рынок, а в будущем она может быть расширена для поддержки торговых стратегий на спотовом рынке.
  2. Многопродуктовые контракты: Благодаря добавлению поддержки нескольких контрактов стратегии могут отслеживать и торговать несколькими цифровыми валютами одновременно, что повышает эффективность использования капитала.
  3. Интеграция машинного обучения: В сочетании с алгоритмами машинного обучения он дополнительно повышает точность оценки тенденций и уровень интеллектуальности стратегий.
  4. Оптимизация управления рисками: Дальнейшая оптимизация механизмов управления рисками, таких как динамическая корректировка коэффициентов кредитного плеча, многоуровневые механизмы стоп-лосса и тейк-профита, для повышения надежности стратегии.

Подвести итог

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

Платформа Inventor — это настоящая сокровищница знаний и стратегий количественной торговли, каждая из которых воплощает мудрость и опыт её разработчиков. Мы приглашаем всех желающих изучить здесь ценные торговые стратегии и методики. Благодарим всех наших новаторов и пользователей, готовых делиться опытом. Именно благодаря вашему вкладу эта платформа стала важнейшей площадкой для обучения и обмена опытом в области количественной торговли, помогая каждому совершенствовать свои навыки и знания.

”`python “‘backtest start: 2024-11-26 00:00:00 end: 2024-12-03 00:00:00 period: 1d basePeriod: 1d exchanges: [{“eid”:“Futures_Binance”,“currency”:“BTC_USDT”}] “’

import json, talib import numpy as np

class TrendStrategy: def init(self): # 基本设置 self._Currency = TradeCurrency self._Interval = Interval self._UseQuarter = UseQuarter self._UseContract = TradeCurrency + (‘.swap’ if self._UseQuarter else ‘.quarter’) self._OnlyTrendJudgment = OnlyTrendJudgment self._EnableMessageSend = EnableMessageSend # 趋势判断 self._RunInKLinePeriod = RunInKLinePeriod self._KLinePeriod = KLinePeriod self._EmaLength = EmaLength self._EmaCoefficient = EmaCoefficient self._UseStddev = UseStddev self._UseRecordsMiddleValue = UseRecordsMiddleValue self._StddevLength = StddevLength self._StddevDeviations = StddevDeviations # 下单设置 self._MarginLevel = MarginLevel self._OrderSize = OrderSize self._OrderByMargin = OrderByMargin self._OrderMarginPercent = OrderMarginPercent self._PricePrecision = None self._AmountPrecision = None self._OneSizeInCurrentCoin = None self._QuarterOneSizeValue = None # 止盈止损 self._UseStopLoss = UseStopLoss self._StopLossPercent = StopLossPercent self._UseTakeProfit = UseTakeProfit self._TakeProfitPercent = TakeProfitPercent self._UseTrackingTakeProfit = UseTrackingTakeProfit self._UsePositionRetracement = UsePositionRetracement self._TakeProfitTriggerPercent = TakeProfitTriggerPercent self._CallBakcPercent = CallBakcPercent

    # 策略变量
    self._LastBarTime = 0
    self._TrendWhenTakeProfitOrStopLoss = 0
    self._HadStopLoss = False
    self._TriggeredTakeProfit = False
    self._PeakPriceInPosition = 0
    self._HadTakeProfit = False
    self._PriceCrossEMAStatus = 0

    # 统计变量
    self._InitAsset = 0
    self._ProfitLocal = 0
    self._TakeProfitCount = 0
    self._TradeCount = 0
    self.StrategyRunTimeStampString = "strategy_run_time"
    self._StrategyDatas = {"start_run_timestamp": 0, "others": ""}
    self._UserDatas = None

    # 相对固定参数
    self._MaintenanceMarginRate = 0.004
    self._TakerFee = 0.0005
    self._IsUsdtStandard = False

    # 获取合约信息
    ticker = _C(exchange.GetTicker, self._UseContract)
    marketInfo = exchange.GetMarkets()[self._UseContract]
    Log('获取市场信息:', marketInfo)
    self._PricePrecision = marketInfo['PricePrecision']
    self._AmountPrecision = marketInfo['AmountPrecision']
    self._OneSizeInCurrentCoin = marketInfo['CtVal']
    self._QuarterOneSizeValue = marketInfo['CtVal']

    exchange.SetCurrency(self._Currency)
    exchange.SetMarginLevel(self._UseContract, self._MarginLevel)
    exchange.SetPrecision(self._PricePrecision, self._AmountPrecision)

    # 初始化数据
def initDatas(self):

    self.saveStrategyRunTime()
    self.readUserDataLocal()

    self._InitAsset = self._UserDatas["init_assets"]
    self._ProfitLocal = self._UserDatas["profit_local"]
    self._TakeProfitCount = self._UserDatas["take_profit_count"]
    self._TradeCount = self._UserDatas["trade_count"]

    if self._OrderByMargin:
        self.getRealOrderSize(-1, self._OrderSize)
        Log("已经重新计算下单张数:", self._OrderSize)
    if self._UseTakeProfit and self._UseTrackingTakeProfit:
        raise Exception("止盈和回调止盈不能同时使用!")

# 设置合约
def setContract(self):
    self._IsUsdtStandard = "USDT" in self._Currency

    exchange.SetCurrency(self._Currency)
    if self._UseQuarter:
        exchange.SetContractType("quarter")
    else:
        exchange.SetContractType("swap")

# 保存程序起始运行时间 秒级时间戳
def saveStrategyRunTime(self):
    local_data_strategy_run_time = _G(self.StrategyRunTimeStampString)

    if local_data_strategy_run_time is None:
        self._StrategyDatas["start_run_timestamp"] = Unix()
        _G(self.StrategyRunTimeStampString, self._StrategyDatas["start_run_timestamp"])
    else:
        self._StrategyDatas["start_run_timestamp"] = local_data_strategy_run_time

# 设置程序起始运行时间 秒级时间戳
def setStrategyRunTime(self, timestamp):
    _G(self.StrategyRunTimeStampString, timestamp)
    self._StrategyDatas["start_run_timestamp"] = timestamp

# 计算两个时间戳之间的天数,参数是秒级时间戳
def getDaysFromTimeStamp(self, start_time, end_time):
    if end_time < start_time:
        return 0

    return (end_time - start_time) // (60 * 60 * 24)

# 保存数据到本地
def saveUserDatasLocal(self):
    self._UserDatas = {
        "init_assets": self._InitAsset,
        "profit_local": self._ProfitLocal,
        "take_profit_count": self._TakeProfitCount,
        "trade_count": self._TradeCount
    }
    # 存储到本地
    _G(exchange.GetLabel(), self._UserDatas)
    Log("已把所有数据保存到本地.")

# 读取用户本地数据,程序启动时候运行一次
def readUserDataLocal(self):
    user_data = _G(exchange.GetLabel())
    if user_data is None:
        self._InitAsset = self.getAccountAsset(_C(exchange.GetPosition), _C(exchange.GetAccount), _C(exchange.GetTicker))
        self._UserDatas = {
            "init_assets": self._InitAsset,
            "profit_local": 0,
            "take_profit_count": 0,
            "trade_count": 0
        }
    else:
        self._UserDatas = user_data

# 清除用户本地数据,交互按钮点击运行
def clearUserDataLocal(self):
    _G(exchange.GetLabel(), None)
    Log(exchange.GetLabel(), ":已清除本地数据.")

# 策略交互
def runCmd(self):
    cmd = GetCommand()

    if cmd:
        # 检测交互命令
        Log("接收到的命令:", cmd, "#FF1CAE")
        if cmd.startswith("ClearLocalData:"):
            # 清除本地数据
            self.clearUserDataLocal()
        elif cmd.startswith("SaveLocalData:"):
            # 保存数据到本地
            self.saveUserDatasLocal()
        elif cmd.startswith("ClearLog:"):
            # 清除日志
            log_reserve = cmd.replace("ClearLog:", "")
            LogReset(int(log_reserve))
        elif cmd.startswith("OrderSize:"):
            # 修改下单张数
            if self._OrderByMargin:
                Log("已经使用保证金数量来下单,无法直接修改下单数量!")
            else:
                order_size = int(cmd.replace("OrderSize:", ""))
                self._OrderSize = order_size
                Log("下单张数已经修改为:", self._OrderSize)
        elif cmd.startswith("OrderMarginPercent:"):
            # 修改下单保证金百分比
            if self._OrderByMargin:
                order_margin_percent = float(cmd.replace("OrderMarginPercent:", ""))
                self._OrderMarginPercent = order_margin_percent
                Log("下单保证金百分比:", self._OrderMarginPercent, "%")
            else:
                Log("没有打开根据保证金数量下单,无法修改下单保证金百分比!")

# 交易函数
def orderDirectly(self, distance, price, amount):
    tradeFunc = None

    if amount <= 0:
        raise Exception("设置的参数有误,下单数量已经小于0!")

    if distance == "buy":
        tradeFunc = exchange.Buy
    elif distance == "sell":
        tradeFunc = exchange.Sell
    elif distance == "closebuy":
        tradeFunc = exchange.Sell
    else:
        tradeFunc = exchange.Buy

    exchange.SetDirection(distance)
    return tradeFunc(price, amount)

def openLong(self, price, amount):
    real_amount = self.getRealOrderSize(price, amount)
    return self.orderDirectly("buy", price, real_amount)

def openShort(self, price, amount):
    real_amount = self.getRealOrderSize(price, amount)
    return self.orderDirectly("sell", price, real_amount)

def coverLong(self, price, amount):
    return self.orderDirectly("closebuy", price, amount)

def coverShort(self, price, amount):
    return self.orderDirectly("closesell", price, amount)

# 重新计算下单数量
def getRealOrderSize(self, price, amount):
    real_price = price if price != -1 else _C(exchange.GetTicker).Last
    if self._OrderByMargin:
        if self._IsUsdtStandard:

            self._OrderSize = _N(self._InitAsset * (self._OrderMarginPercent / 100) / real_price * self._MarginLevel / self._OneSizeInCurrentCoin, self._AmountPrecision)  # u本位数量(杠杆放大数量)

        else:
            self._OrderSize = _N(self._InitAsset * (self._OrderMarginPercent / 100) * self._MarginLevel * real_price / self._QuarterOneSizeValue, self._AmountPrecision)  # 币本位数量(杠杆放大数量)
    else:
        self._OrderSize = amount
    return self._OrderSize

# 获取单个持仓占用保证金
def getSinglePositionMargin(self, position, ticker):
    position_margin = 0

    if len(position) > 0:
        if self._IsUsdtStandard:
            position_margin = position[0].Amount * self._OneSizeInCurrentCoin * ticker.Last / self._MarginLevel
        else:
            position_margin = position[0].Amount * self._QuarterOneSizeValue / ticker.Last / self._MarginLevel

    return position_margin

# 获取单向持仓的收益和收益%
def getSinglePositionProfit(self, position, ticker):
    if len(position) == 0:
        return [0, 0]

    price = ticker.Last
    position_margin = self.getSinglePositionMargin(position, ticker)

    position_profit_percent = (price - position[0].Price) / position[0].Price * self._MarginLevel if position[0].Type == PD_LONG else (position[0].Price - price) / position[0].Price * self._MarginLevel
    position_profit = position_margin * position_profit_percent

    return [position_profit, position_profit_percent]

# 计算强平价格
def calculateForcedPrice(self, account, position, ticker):
    position_profit = 0
    total_avail_balance = 0
    forced_price = 0

    position_margin = self.getSinglePositionMargin(position, ticker)
    [position_profit, position_profit_percent] = self.getSinglePositionProfit(position, ticker)

    if self._IsUsdtStandard:
        total_avail_balance = account.Balance + position_margin + account.FrozenBalance - position_profit if position_profit > 0 else account.Balance + position_margin + account.FrozenBalance
        if position[0].Type == PD_LONG:
            forced_price = ((self._MaintenanceMarginRate + self._TakerFee) * self._MarginLevel * account.FrozenBalance - total_avail_balance) / self._OneSizeInCurrentCoin + (position[0].Amount * position[0].Price) / (position[0].Amount - (self._MaintenanceMarginRate + self._TakerFee) * position[0].Amount)
        else:
            forced_price = ((self._MaintenanceMarginRate + self._TakerFee) * self._MarginLevel * account.FrozenBalance - total_avail_balance) / self._OneSizeInCurrentCoin - (position[0].Amount * position[0].Price) / (-1 * position[0].Amount - (self._MaintenanceMarginRate + self._TakerFee) * position[0].Amount)
    else:
        total_avail_balance = account.Stocks + position_margin + account.FrozenStocks - position_profit if position_profit > 0 else account.Stocks + position_margin + account.FrozenStocks
        if position[0].Type == PD_LONG:
            forced_price = (self._MaintenanceMarginRate * position[0].Amount + position[0].Amount) / (total_avail_balance / self._QuarterOneSizeValue + position[0].Amount / position[0].Price)
        else:
            forced_price = (self._MaintenanceMarginRate * position[0].Amount - position[0].Amount) / (total_avail_balance / self._QuarterOneSizeValue - position[0].Amount / position[0].Price)

    if forced_price < 0:
        forced_price = 0

    return forced_price

# 计算最大可下单张数
def getMaxOrderSize(self, margin_level, ticker, account):
    max_order_size = 0

    if self._IsUsdtStandard:
        max_order_size = account.Balance * margin_level / (self._OneSizeInCurrentCoin * ticker.Last)
    else:
        max_order_size = account.Stocks * ticker.Last / self._QuarterOneSizeValue * margin_level

    return _N(max_order_size, self._AmountPrecision)

# 获取账户资产
def getAccountAsset(self, position, account, ticker):
    # 计算不同情况下的账户初始资产
    account_asset = 0
    position_margin = self.getSinglePositionMargin(position, ticker)

    if self._IsUsdtStandard:
        if len(position) > 0:
            account_asset = account.Balance + account.FrozenBalance + position_margin
        else:
            account_asset = account.Balance + account.FrozenBalance
    else:
        if len(position) > 0:
            account_asset = account.Stocks + account.FrozenStocks + position_margin
        else:
            account_asset = account.Stocks + account.FrozenStocks

    return account_asset

# 收益统计
def calculateProfit(self, ticker):
    # 重新获取一下账户持仓与资产
    position = _C(exchange.GetPosition)
    account = _C(exchange.GetAccount)
    # 当前总收益 - 上一次总收益 = 本次的收益
    current_profit = (self.getAccountAsset(position, account, ticker) - self._InitAsset) - self._ProfitLocal
    self._ProfitLocal += current_profit

    if current_profit > 0:
        self._TakeProfitCount += 1
    self._TradeCount += 1

    LogProfit(_N(self._ProfitLocal, 4), "        本次收益:", _N(current_profit, 6))
    self.saveUserDatasLocal()

# 是否还够资金下单
def isEnoughAssetToOrder(self, order_size, ticker):
    is_enough = True
    account = _C(exchange.GetAccount)

    if self._IsUsdtStandard:
        if account.Balance < order_size * ticker.Last * self._OneSizeInCurrentCoin / self._MarginLevel:
            is_enough = False
    else:
        if account.Stocks < order_size * self._QuarterOneSizeValue / ticker.Last / self._MarginLevel:
            is_enough = False

    return is_enough

# 按照K线周期运行策略核心
def runInKLinePeriod(self, records):
    bar_time = records[-1].Time
    if self._RunInKLinePeriod and self._LastBarTime == bar_time:
        return False

    self._LastBarTime = bar_time
    return True

# 趋势判断模块(可编辑具体指标)
def trendJudgment(self, records):
    # 检查价格是否穿过均线
    def checkPriceCrossEma(price, ema_value):
        if self._PriceCrossEMAStatus == 0:
            if price <= ema_value:
                self._PriceCrossEMAStatus = -1
            else:
                self._PriceCrossEMAStatus = 1
        elif (self._PriceCrossEMAStatus == -1 and price >= ema_value) or (self._PriceCrossEMAStatus == 1 and price <= ema_value):
            self._PriceCrossEMAStatus = 2  # 完成穿过

    # EMA的多空判断
    ema_long = False
    ema_short = False
    price = records[-2].Close  # 已经收盘的K线的收盘价格
    ema = TA.EMA(records, self._EmaLength)
    ema_value = ema[-2]  # 收盘K线对应ema值
    ema_upper = ema_value * (1 + self._EmaCoefficient)
    ema_lower = ema_value * (1 - self._EmaCoefficient)

    checkPriceCrossEma(price, ema_value)
    if price > ema_upper:
        ema_long = True
    elif price < ema_lower:
        ema_short = True

    # 标准差判断
    in_trend = False
    if self._UseStddev:
        records_data = []
        for i in range(len(records)):
            records_data.append((records[i].High + records[i].Low) / 2 if self._UseRecordsMiddleValue else records[i].Close)

        records_data = np.array(records_data)  # 将 list 转换为 np.array
        stddev = np.std(records_data, ddof=1)  # 使用 numpy 计算标准差
        if stddev > self._StddevDeviations:
            in_trend = True
    else:
        in_trend = True

    # 趋势判断
    long = in_trend and ema_long 
    short = in_trend and ema_short

    if long:
        Log("当前趋势为:多", self._EnableMessageSend and "@" or "#00FF7F")
    elif short:
        Log("当前趋势为:空", self._EnableMessageSend and "@" or "#FF0000")
    else:
        Log("当前趋势为:震荡", self._EnableMessageSend and "@" or "#007FFF")

    return [long, short]

# 止损
def stopLoss(self, position, ticker):
    stop_loss_price = 0
    price = ticker.Last

    if len(position) == 1 and self._UseStopLoss:
        if position[0].Type == PD_LONG:
            stop_loss_price = position[0].Price * (1 - self._StopLossPercent / 100)
            if price < stop_loss_price:
                self.coverLong(-1, position[0].Amount)
                self.calculateProfit(ticker)
                self._TrendWhenTakeProfitOrStopLoss = 1
                self._HadStopLoss = True
                Log("多单止损。止损价格:", _N(stop_loss_price, 6), ", 持仓价格:", _N(position[0].Price), self._EnableMessageSend and "@" or "#FF1CAE")
        elif position[0].Type == PD_SHORT:
            stop_loss_price = position[0].Price * (1 + self._StopLossPercent / 100)
            if price > stop_loss_price:
                self.coverShort(-1, position[0].Amount)
                self.calculateProfit(ticker)
                self._TrendWhenTakeProfitOrStopLoss = -1
                self._HadStopLoss = True
                Log("空单止损。止损价格:", _N(stop_loss_price, 6), ", 持仓价格:", _N(position[0].Price), self._EnableMessageSend and "@" or "#FF1CAE")

# 止盈
def takeProfit(self, position, ticker):
    take_profit_price = 0
    price = ticker.Last

    if len(position) == 1 and self._UseTakeProfit:
        if position[0].Type == PD_LONG:
            take_pr