
밤새도록 프레임워크를 구축하기 위한 코드를 작성하고, UI를 디자인하고, 다양한 디자인 세부 사항과 메커니즘을 직접 다루지 않고도 손쉽게 양적 거래를 시작하고 바로 시작할 수 있다고 생각해 본 적이 있나요? FMZ 양적 플랫폼에서는 모든 것이 가능합니다. 고급 프로그래밍 배경 지식이 필요 없고, 복잡한 배포 프로세스에 대해 걱정할 필요도 없습니다. 컴퓨터와 계정만 있으면 어디서든 양적 분석을 시작할 수 있습니다. 이 글을 통해 FMZ를 처음부터 빠르게 시작하고, 자동 거래의 매력을 경험하고, 데이터와 전략을 사용하여 시장 리듬을 마스터하는 방법을 알아보세요. 초보자이든 효율성을 개선하고자 하는 베테랑이든 이 여정은 시도해 볼 만한 가치가 있습니다.
저는 종종 플랫폼 초보자들과 소통하고 채팅을 합니다. 양적 거래를 처음 시작하는 사람들은 대개 전체적인 설계 과정에 혼란을 느낀다. 거래 아이디어가 떠오르면 어디서부터 시작해야 할지 모르겠고 압도당하는 기분이 들 때가 많습니다.
다음에 대해 혼란스러워요:
위의 혼란을 함께 풀어보도록 하겠습니다.
양적 거래의 세계에서 전략 설계는 종종 끝이 없는 탐험의 여정입니다. 여러분은 지표를 작성해 보거나, 매수 및 매도 신호를 맹목적으로 따르려고 했을 수도 있지만, 실제로 가장 큰 효과를 볼 수 있는 것은 “눈에 띄고, 조정 가능하며, 안정적인” 전략 시스템입니다. FMZ 양적 플랫폼을 기반으로, ‘정시에 진행되는’ 실제 경험을 할 수 있습니다. 매개변수 설정, 차트 표시, 대화형 기능, 손익 계산 등 간단한 전략을 구축하여 전략의 설계 요구 사항을 완벽하게 충족합니다.
전략 아이디어는 ATR을 기반으로 한 단계별 포지션 증가 전략, 단계별 그리드 포지션 구축 로직(롱 및 숏 양방향), ATR 적응형 변동성 계산, 포지션 청산 로직(시장이 중심축으로 반전할 때)입니다.
이 전략은 다음과 같은 설계 요구 사항을 기반으로 합니다.
두 개의 배열을 설정하여 위치의 점진적인 증가를 제어합니다.
var arrUp = null
var arrDown = null
위치를 추가할 때마다 위치 정보가 배열에 푸시되므로 위치를 제어하고 전략 실시간 인터페이스에서 데이터를 표시하는 것이 더 쉬워집니다.
가격 돌파 수준에 따라 포지션을 개시하거나 종료합니다. 단순화를 위해 포지션 개시와 종료 모두 간단하고 효과적인 시장가 주문을 사용합니다.
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)
}
재고를 비우고 이를 처리하는 함수를 사용합니다. 일부 데이터 구조는 재고가 정리될 때마다 재설정되어야 하므로 정리 기능을 대화형 모듈에서 재사용할 수 있는 함수로 캡슐화해야 합니다.
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입니다. 각 등급마다 다른 가격 한도가 계산됩니다.
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에서 상호작용 기능을 디자인하고, 인벤토리를 정리하고, 일시 정지하고, 일시 정지를 해제하고, 매개변수를 수정하는 등의 작업을 할 수 있습니다. FMZ에서 상호작용을 디자인하는 것은 매우 편리하며, 플랫폼은 다양한 상호작용 컨트롤을 제공합니다. 전략에 대화형 컨트롤만 추가하고, 전략 코드에서 메시지를 수신할 때 다양한 인식 및 처리 코드를 작성하면 됩니다.
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 앱, 타사 인터페이스 등
Log([r[r.length - 1].Time, "long", close, tradeAmount], "@") // 消息推送
푸시 알림 받기(FMZ 앱 및 기타 앱도 푸시 알림을 받습니다):

손익을 계산하는 함수는 포지션이 마감될 때마다 호출되어 손익을 계산하고 손익 곡선을 출력합니다.
function calcProfit() {
var initAcc = _G("initAcc")
var nowAcc = _C(exchange.GetAccount)
var profit = nowAcc.Equity - initAcc.Equity
return profit
}
FMZ를 사용하세요_G()기능, 전략 진행 복구 메커니즘을 설계하는 것은 쉽습니다.
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 단위로 주문을 하는 방법을 묻습니다.
if (isAmountForUSDT) {
tradeAmount = tradeAmount * 1.05 / close
}
tradeAmount = _N(tradeAmount, amountPrecision)
사실 매우 간단합니다. 금액을 가격으로 나누면 됩니다.
위험 관리를 위해 항상 계좌에 일정 금액의 자금을 비축하고 싶다면, 다음과 같은 간단한 메커니즘을 설계할 수 있습니다.
var balance = acc.Balance
if (balance - initAcc.Equity * reserve < tradeAmount * close) {
continue
}
실제 시장을 운영할 때는 계정 자본, 전략 상태, 전략 포지션, 주문 정보, 시장 차트 등을 포함한 전략을 관찰하는 것이 반드시 필요합니다. 이러한 정보는 다음과 같이 설계되었습니다.
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% 시뮬레이션할 수 없다는 걸 알고 있을 겁니다. 백테스팅의 주요 목적은 전략의 논리성을 테스트하고, 전략의 견고성을 테스트하고, 기본 기능을 테스트하는 것입니다.


매개변수 설계:

상호작용 디자인:

전략 소스 코드:
/*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)
}
}
이 전략은 오로지 교육 목적으로만 사용됩니다. 실제 거래에 사용할 수 있고 현재는 수익성이 있지만, 장기적인 효과를 시험하기까지는 시간이 걸릴 것입니다. 전략 수립 부분에는 여전히 최적화의 여지가 있으며, 이를 통해 반복적인 작업을 피하고 프로그램 효율성을 개선할 수 있습니다. 전략 논리도 더욱 최적화될 수 있습니다.

GPT의 시적 요약:
실제 거래는 긴 여정이다. 언제 돌아오든 당신은 오직 마음의 평화만을 원할 것입니다. 당신이 포지션을 열 때마다, 당신은 광대한 시장에 희망의 빛을 뿌리게 됩니다. 손실을 멈출 때마다 바람과 비 속에서도 더욱 굳건하게 전진하는 법을 배우게 됩니다. 시장은 조류와 같고, 이익과 손실은 꿈과 같습니다. 우리는 숫자라는 파도의 꼭대기에서 춤을 추고 전략이라는 등대 아래에서 지켜본다. 당신과 내가 이 긴 여정에서 길을 잃지 않고 외로움을 두려워하지 않으며, 마침내 우리에게 속한 빛에 도달할 수 있기를 바랍니다.
이 글은 완전한 전략을 소개할 뿐만 아니라, 더 중요하게는 “체계적인” 전략 개발 아이디어를 소개합니다. 전략 설계, 현황 관리, 위험 관리, 차트 상호작용부터 실제 구현까지 반복적으로 재사용 가능한 템플릿 세트이며, 양적 거래가 전문화되는 방향으로 나아가는 유일한 방법이기도 합니다.
FMZ 플랫폼을 사용하여 어떤 신호도 놓치지 않는 자동 거래 시스템을 직접 구축하시기 바랍니다.
여러분의 읽어주시고 응원해주셔서 감사합니다. 이 전략은 교육 목적으로만 사용됩니다. 실제 거래에서는 주의해서 사용하시기 바랍니다.