Type/to search
8
Follow
1364
Followers
Количественное путешествие начинается с FMZ
Discussions
Created 2025-04-18 09:31:42  Updated 2025-04-26 11:50:01
 0
 1297

img

введение

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

Замешательство новичков в количественной торговле

Я часто общаюсь и общаюсь с новичками платформы. Новички в количественной торговле обычно не понимают всего процесса проектирования. Когда у меня возникают торговые идеи, я часто не знаю, с чего начать, и чувствую себя подавленным.

Смущает следующее:

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

Давайте вместе разрешим эту путаницу.

Объяснение дизайна

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

Идея стратегии заключается в пошаговой стратегии увеличения позиции на основе ATR, пошаговой логике построения сетки позиций (длинные и короткие двунаправленные), адаптивном расчете волатильности ATR и логике ликвидации позиции (когда рынок разворачивается к центральной оси).

Эта стратегия основана на следующих требованиях к проектированию:

Добавляйте позиции и закрывайте позиции в соответствии с ценовыми прорывами на разных уровнях

Создайте два массива для управления постепенным увеличением позиций.

javascript
var arrUp = null var arrDown = null

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

Открывать и закрывать позиции в соответствии с уровнем прорыва цены. Для простоты и открытие, и закрытие позиций используют рыночные ордера, которые просты и эффективны.

javascript
if (close > up && i >= arrUp.length && !isPaused) { var id = exchange.CreateOrder(symbol, "sell", -1, tradeAmount) if (!id) { Log("下单失败") continue } arrUp.push({"symbol": symbol, "ratio": (i + 1), "amount": tradeAmount, "price": close}) _G("arrUp", arrUp) arrSignal.push([r[r.length - 1].Time, "short", close, tradeAmount]) Log([r[r.length - 1].Time, "short", close, tradeAmount], "@") } else if (close < down && i >= arrDown.length && !isPaused) { var id = exchange.CreateOrder(symbol, "buy", -1, tradeAmount) if (!id) { Log("下单失败") continue } arrDown.push({"symbol": symbol, "ratio": (i + 1), "amount": tradeAmount, "price": close}) _G("arrDown", arrDown) arrSignal.push([r[r.length - 1].Time, "long", close, tradeAmount]) Log([r[r.length - 1].Time, "long", close, tradeAmount], "@") } else if (((arrUp.length > 0 && close < mid) || (arrDown.length > 0 && close > mid)) && !isPaused) { clear(pos, r) }

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

javascript
function clear(positions, r) { var close = r[r.length - 1].Close for (var p of positions) { if (p.Type == PD_LONG) { var id = exchange.CreateOrder(symbol, "closebuy", -1, p.Amount) if (!id) { Log("下单失败") continue } arrSignal.push([r[r.length - 1].Time, "closelong", close, p.Amount]) Log([r[r.length - 1].Time, "closelong", close, p.Amount], "@") } else if (p.Type == PD_SHORT) { var id = exchange.CreateOrder(symbol, "closesell", -1, p.Amount) if (!id) { Log("下单失败") continue } arrSignal.push([r[r.length - 1].Time, "closeshort", close, p.Amount]) Log([r[r.length - 1].Time, "closeshort", close, p.Amount], "@") } } arrUp = [] arrDown = [] _G("arrUp", arrUp) _G("arrDown", arrDown) var profit = calcProfit() LogProfit(profit) }

Распределение позиций шаг за шагом

Он разделен на несколько уровней, максимальный уровень — maxRatio. Для каждого уровня рассчитывается свой ценовой порог.

javascript
for (var i = 0; i < maxRatio; i++) { var up = open + atr[atr.length - 1] * (i + 1) var mid = open var down = open - atr[atr.length - 1] * (i + 1) atrs.push([open, (i + 1), atr]) var tradeAmount = baseAmount * Math.pow(2, i) if (isAmountForUSDT) { tradeAmount = tradeAmount * 1.05 / close } tradeAmount = _N(tradeAmount, amountPrecision) var balance = acc.Balance if (balance - initAcc.Equity * reserve < tradeAmount * close) { continue } // ... }

Поддержка динамической настройки параметров, паузы, быстрой очистки и других взаимодействий.

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

javascript
var cmd = GetCommand() if (cmd) { Log("交互指令:", cmd) var arrCmd = cmd.split(":") if (arrCmd.length == 2) { var strCmd = arrCmd[0] var param = parseFloat(arrCmd[1]) if (strCmd == "atrPeriod") { atrPeriod = param Log("修改ATR参数:", atrPeriod) } } else { if (cmd == "isPaused" && !isPaused) { isPaused = true Log("暂停交易") } else if (cmd == "isPaused" && isPaused) { isPaused = false Log("取消暂停交易") } else if (cmd == "clearAndPaused") { clear(pos, r) isPaused = true Log("清仓、暂停交易") } } }

С механизмом напоминания об открытии/закрытии

При открытии или закрытии стратегии вы можете легко отправлять сообщенияПочта, FMZ APP, сторонний интерфейс и т. д.

javascript
Log([r[r.length - 1].Time, "long", close, tradeAmount], "@") // 消息推送

Получать push-уведомления (приложение FMZ и другие приложения также будут получать push-уведомления):

img

Статистика в реальном времени и отображение прибылей и позиций

Функция расчета прибыли и убытка вызывается каждый раз при закрытии позиции для расчета прибыли и убытка и вывода кривой прибыли и убытка.

javascript
function calcProfit() { var initAcc = _G("initAcc") var nowAcc = _C(exchange.GetAccount) var profit = nowAcc.Equity - initAcc.Equity return profit }

Поддержка сохранения состояния (восстановление точки останова)

Использовать ФМЗ_G()Функция, легко разработать механизм восстановления прогресса стратегии.

javascript
if (isReset) { _G(null) LogProfitReset() LogReset(1) c.reset() } arrUp = _G("arrUp") if (!arrUp) { arrUp = [] _G("arrUp", arrUp) } arrDown = _G("arrDown") if (!arrDown) { arrDown = [] _G("arrDown", arrDown) }

Проектирование размещения заказов по сумме

При торговле контрактами объем заказа в интерфейсе заказа представляет собой количество контрактов, поэтому пользователи часто спрашивают, как разместить заказ в количестве Us:

javascript
if (isAmountForUSDT) { tradeAmount = tradeAmount * 1.05 / close } tradeAmount = _N(tradeAmount, amountPrecision)

На самом деле это очень просто: просто разделите сумму на цену.

Расчет коэффициента резервирования

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

javascript
var balance = acc.Balance if (balance - initAcc.Equity * reserve < tradeAmount * close) { continue }

Визуализация диаграммы

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

javascript
if (isShowPlot) { r.forEach(function(bar, index) { c.begin(bar) for (var i in atrs) { var arr = atrs[i] var up = arr[0] + arr[2][index] * arr[1] var mid = arr[0] var down = arr[0] - arr[2][index] * arr[1] c.plot(up, 'up_' + (i + 1)) c.plot(mid, 'mid_' + (i + 1)) c.plot(down, 'down_' + (i + 1)) } for (var signal of arrSignal) { if (signal[0] == bar.Time) { c.signal(signal[1], signal[2], signal[3]) } } c.close() }) } // ... var orderTbl = {"type": "table", "title": "order", "cols": ["symbol", "type", "ratio", "price", "amount"], "rows": []} for (var i = arrUp.length - 1; i >= 0; i--) { var order = arrUp[i] orderTbl["rows"].push([order["symbol"], "short", order["ratio"], order["price"], order["amount"]]) } for (var i = 0; i < arrDown.length; i++) { var order = arrDown[i] orderTbl["rows"].push([order["symbol"], "long", order["ratio"], order["price"], order["amount"]]) } var posTbl = {"type": "table", "title": "pos", "cols": ["symbol", "type", "price", "amount"], "rows": []} for (var i = 0; i < pos.length; i++) { var p = pos[i] posTbl["rows"].push([p.Symbol, p.Type == PD_LONG ? "long" : "short", p.Price, p.Amount]) } LogStatus(_D(), "初始权益:" + initAcc.Equity, ", 当前权益:" + acc.Equity, ", 运行状态:" + (isPaused ? "暂停交易" : "运行中"), "\n`" + JSON.stringify(orderTbl) + "`\n", "`" + JSON.stringify(posTbl) + "`")

В конечном итоге более 200 строк кода реализовали полноценную стратегию, которую можно протестировать на исторических данных и внедрить в реальную торговлю. Мы достигли нашей конечной цели: создать комплексную количественную торговую систему на FMZ, сочетающую в себе «визуализацию + взаимодействие + автоматизацию».

Эффект от стратегии и результаты бэктестинга

Тестирование на исторических данных носит исключительно справочный характер. Те, кто занимается количественной торговлей, знают, что «бэктестинг» не может на 100% смоделировать реальный сценарий. Основная цель бэктестинга — проверка логики стратегии, надежности стратегии, базовое функциональное тестирование и т. д.

img

img

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

Параметры конструкции:

img

Проектирование взаимодействия:

img

Исходный код стратегии:

javascript
/*backtest start: 2024-04-27 18:40:00 end: 2025-04-10 00:00:00 period: 15m basePeriod: 15m exchanges: [{"eid":"Futures_Binance","currency":"ETH_USDT","balance":100}] */ var atrPeriod = 20 var arrUp = null var arrDown = null var arrSignal = [] function calcProfit() { var initAcc = _G("initAcc") var nowAcc = _C(exchange.GetAccount) var profit = nowAcc.Equity - initAcc.Equity return profit } function clear(positions, r) { var close = r[r.length - 1].Close for (var p of positions) { if (p.Type == PD_LONG) { var id = exchange.CreateOrder(symbol, "closebuy", -1, p.Amount) if (!id) { Log("下单失败") continue } arrSignal.push([r[r.length - 1].Time, "closelong", close, p.Amount]) Log([r[r.length - 1].Time, "closelong", close, p.Amount], "@") } else if (p.Type == PD_SHORT) { var id = exchange.CreateOrder(symbol, "closesell", -1, p.Amount) if (!id) { Log("下单失败") continue } arrSignal.push([r[r.length - 1].Time, "closeshort", close, p.Amount]) Log([r[r.length - 1].Time, "closeshort", close, p.Amount], "@") } } arrUp = [] arrDown = [] _G("arrUp", arrUp) _G("arrDown", arrDown) var profit = calcProfit() LogProfit(profit) } function main() { var symbolInfo = symbol.split(".") if (symbolInfo.length != 2) { throw "error symbol:" + symbol } else { exchange.SetCurrency(symbolInfo[0]) exchange.SetContractType(symbolInfo[1]) } exchange.SetPrecision(pricePrecision, amountPrecision) let c = KLineChart({ overlay: true }) if (isReset) { _G(null) LogProfitReset() LogReset(1) c.reset() } arrUp = _G("arrUp") if (!arrUp) { arrUp = [] _G("arrUp", arrUp) } arrDown = _G("arrDown") if (!arrDown) { arrDown = [] _G("arrDown", arrDown) } var initAcc = _G("initAcc") if (!initAcc) { initAcc = _C(exchange.GetAccount) _G("initAcc", initAcc) } var isPaused = false while (true) { var atrs = [] var r = _C(exchange.GetRecords, symbol) var pos = _C(exchange.GetPositions, symbol) var acc = _C(exchange.GetAccount) var open = r[r.length - 1].Open var close = r[r.length - 1].Close var atr = TA.ATR(r, atrPeriod) for (var i = 0; i < maxRatio; i++) { var up = open + atr[atr.length - 1] * (i + 1) var mid = open var down = open - atr[atr.length - 1] * (i + 1) atrs.push([open, (i + 1), atr]) var tradeAmount = baseAmount * Math.pow(2, i) if (isAmountForUSDT) { tradeAmount = tradeAmount * 1.05 / close } tradeAmount = _N(tradeAmount, amountPrecision) var balance = acc.Balance if (balance - initAcc.Equity * reserve < tradeAmount * close) { continue } if (close > up && i >= arrUp.length && !isPaused) { var id = exchange.CreateOrder(symbol, "sell", -1, tradeAmount) if (!id) { Log("下单失败") continue } arrUp.push({"symbol": symbol, "ratio": (i + 1), "amount": tradeAmount, "price": close}) _G("arrUp", arrUp) arrSignal.push([r[r.length - 1].Time, "short", close, tradeAmount]) Log([r[r.length - 1].Time, "short", close, tradeAmount], "@") } else if (close < down && i >= arrDown.length && !isPaused) { var id = exchange.CreateOrder(symbol, "buy", -1, tradeAmount) if (!id) { Log("下单失败") continue } arrDown.push({"symbol": symbol, "ratio": (i + 1), "amount": tradeAmount, "price": close}) _G("arrDown", arrDown) arrSignal.push([r[r.length - 1].Time, "long", close, tradeAmount]) Log([r[r.length - 1].Time, "long", close, tradeAmount], "@") } else if (((arrUp.length > 0 && close < mid) || (arrDown.length > 0 && close > mid)) && !isPaused) { clear(pos, r) } } if (isShowPlot) { r.forEach(function(bar, index) { c.begin(bar) for (var i in atrs) { var arr = atrs[i] var up = arr[0] + arr[2][index] * arr[1] var mid = arr[0] var down = arr[0] - arr[2][index] * arr[1] c.plot(up, 'up_' + (i + 1)) c.plot(mid, 'mid_' + (i + 1)) c.plot(down, 'down_' + (i + 1)) } for (var signal of arrSignal) { if (signal[0] == bar.Time) { c.signal(signal[1], signal[2], signal[3]) } } c.close() }) } var cmd = GetCommand() if (cmd) { Log("交互指令:", cmd) var arrCmd = cmd.split(":") if (arrCmd.length == 2) { var strCmd = arrCmd[0] var param = parseFloat(arrCmd[1]) if (strCmd == "atrPeriod") { atrPeriod = param Log("修改ATR参数:", atrPeriod) } } else { if (cmd == "isPaused" && !isPaused) { isPaused = true Log("暂停交易") } else if (cmd == "isPaused" && isPaused) { isPaused = false Log("取消暂停交易") } else if (cmd == "clearAndPaused") { clear(pos, r) isPaused = true Log("清仓、暂停交易") } } } var orderTbl = {"type": "table", "title": "order", "cols": ["symbol", "type", "ratio", "price", "amount"], "rows": []} for (var i = arrUp.length - 1; i >= 0; i--) { var order = arrUp[i] orderTbl["rows"].push([order["symbol"], "short", order["ratio"], order["price"], order["amount"]]) } for (var i = 0; i < arrDown.length; i++) { var order = arrDown[i] orderTbl["rows"].push([order["symbol"], "long", order["ratio"], order["price"], order["amount"]]) } var posTbl = {"type": "table", "title": "pos", "cols": ["symbol", "type", "price", "amount"], "rows": []} for (var i = 0; i < pos.length; i++) { var p = pos[i] posTbl["rows"].push([p.Symbol, p.Type == PD_LONG ? "long" : "short", p.Price, p.Amount]) } LogStatus(_D(), "初始权益:" + initAcc.Equity, ", 当前权益:" + acc.Equity, ", 运行状态:" + (isPaused ? "暂停交易" : "运行中"), "\n`" + JSON.stringify(orderTbl) + "`\n", "`" + JSON.stringify(posTbl) + "`") Sleep(5000) } }

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

Реальная торговля — это долгий путь

img

Поэтическое резюме от GPT:

Настоящая торговля — это долгий путь. Неважно, когда вы вернетесь, вы ищете только душевного спокойствия. Каждый раз, когда вы открываете позицию, вы сеете свет надежды на огромном рынке; Каждый раз, когда вы прекращаете убыток, вы учитесь двигаться вперед более уверенно, несмотря на ветер и дождь. Рынок подобен приливу, а прибыли и убытки — сну. Мы танцуем на гребне волн чисел и смотрим под маяком стратегии. Пусть мы с тобой в этом долгом путешествии не сбиемся с пути, не побоимся одиночества и, наконец, достигнем света, который принадлежит нам.

Резюме: От разработки стратегии к системному мышлению

В этой статье представлена ​​не только полная стратегия, но, что более важно, идея разработки «систематической» стратегии. От разработки стратегии, управления статусом, контроля рисков, взаимодействия с графиками до фактической реализации — это набор шаблонов, которые можно использовать многократно, и это также единственный способ для количественной торговли перейти к профессионализации.

Надеюсь, вы сможете использовать платформу FMZ для создания собственной автоматизированной торговой системы, которая позволит вам никогда не пропустить ни одного сигнала.

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

Comment
All comments (0)
No data
No data
  • 1
iPhone Download
Forums
PINE Language
© 2015 - ∞ INVENTOR PTE LTD (SG)