디자인 참조를 위해 다중 다양성 이중 EMA 전략을 갖고 싶어하는 커뮤니티 사용자들의 요청에 따라. 이 기사에서는 다중 다양성 이중 EMA 전략을 구현할 것입니다. 편리한 이해와 학습을 위해 전략 코드에 대한 댓글이 작성됩니다. 프로그래밍 및 양적 거래의 더 많은 신입자가 빠르게 시작하도록하십시오.
이중 EMA 전략의 논리는 매우 간단합니다. 즉, 두 개의 EMA입니다. 작은 매개 변수 기간을 가진 EMA (빠른 라인) 과 큰 매개 변수 기간을 가진 EMA (슬로우 라인). 두 라인이 황금색 십자 (빠른 라인이 아래에서 위로 느린 라인을 통과합니다) 를 가지고 있다면 우리는 구매하고 길게 갈 것입니다. 두 라인이 죽은 십자 (빠른 라인이 위에서 아래로 느린 라인을 통과합니다) 를 가지고 있다면 우리는 판매하고 짧게 갈 것입니다. 여기서 EMA를 사용합니다.
그러나 전략은 다종으로 설계되어야하므로 각 품종의 매개 변수는 다를 수 있습니다 (다양한 품종은 다른 EMA 매개 변수를 사용합니다), 따라서 매개 변수를 설계하는 데
매개 변수는 문자열 형태로 설계되어 있으며, 각 매개 변수 코마가 분리되어 있습니다. 전략이 실행되기 시작하면 이러한 문자열을 분석합니다. 실행 논리는 각 종류 (거래 쌍) 에 일치합니다. 회전 된 전략은 각 품종의 시장을 감지하고 거래 조건의 트리거, 차트 인쇄 등을 감지합니다. 모든 품종이 한 번 회전 된 후 데이터를 요약하고 상태 표시줄에 테이블 정보를 표시합니다.
이 전략은 매우 간단하고 초보자 학습에 적합하도록 설계되었으며, 전체 200+ 줄의 코드만 사용합니다.
// Function: cancel all takers of the current trading pair
function cancelAll(e) {
while (true) {
var orders = _C(e.GetOrders)
if (orders.length == 0) {
break
} else {
for (var i = 0 ; i < orders.length ; i++) {
e.CancelOrder(orders[i].Id, orders[i])
Sleep(500)
}
}
Sleep(500)
}
}
// Functionn: calculate the profit/loss in real-time
function getProfit(account, initAccount, lastPrices) {
// account is the current account information, initAccount is the initial account information, lastPrices is the latest price of all varieties
var sum = 0
_.each(account, function(val, key) {
// Iterate through all current assets, calculate the currency difference of assets other than USDT, and the amount difference
if (key != "USDT" && typeof(initAccount[key]) == "number" && lastPrices[key + "_USDT"]) {
sum += (account[key] - initAccount[key]) * lastPrices[key + "_USDT"]
}
})
// Return to the profit and loss of the asset based on the current prices
return account["USDT"] - initAccount["USDT"] + sum
}
// Function: generate chart configuration
function createChartConfig(symbol, ema1Period, ema2Period) {
// symbol is the trading pair, ema1Period is the first EMA period, ema2Period is the second EMA period
var chart = {
__isStock: true,
extension: {
layout: 'single',
height: 600,
},
title : { text : symbol},
xAxis: { type: 'datetime'},
series : [
{
type: 'candlestick', // K-line data series
name: symbol,
id: symbol,
data: []
}, {
type: 'line', // EMA data series
name: symbol + ',EMA1:' + ema1Period,
data: [],
}, {
type: 'line', // EMA data series
name: symbol + ',EMA2:' + ema2Period,
data: []
}
]
}
return chart
}
function main() {
// Reset all data
if (isReset) {
_G(null) // Clear data of all persistent records
LogReset(1) // Clear all logs
LogProfitReset() // Clear all return logs
LogVacuum() //Release the resources occupied by the real bot database
Log("Reset all data", "#FF0000") // Print messages
}
// Parameter analysis
var arrSymbols = symbols.split(",") // Comma-separated string of trading varieties
var arrEma1Periods = ema1Periods.split(",") // Parameter string for splitting the first EMA
var arrEma2Periods = ema2Periods.split(",") // Parameter string for splitting the second EMA
var arrAmounts = orderAmounts.split(",") // Splitting the amount of orders placed for each variety
var account = {} // Variables used for recording current asset messages
var initAccount = {} // Variables used for recording initial asset messages
var currTradeMsg = {} // Variables used for recording whether current BAR trades
var lastPrices = {} // Variables used for recording the latest price of monitored varieties
var lastBarTime = {} // Variable used for recording the time of the last BAR, used to judge the update of BAR when drawing
var arrChartConfig = [] // Used for recording chart configuration message and draw
if (_G("currTradeMsg")) { // For example, restore currTradeMsg data when restarting
currTradeMsg = _G("currTradeMsg")
Log("Restore records", currTradeMsg)
}
// Initialize account
_.each(arrSymbols, function(symbol, index) {
exchange.SetCurrency(symbol)
var arrCurrencyName = symbol.split("_")
var baseCurrency = arrCurrencyName[0]
var quoteCurrency = arrCurrencyName[1]
if (quoteCurrency != "USDT") {
throw "only support quoteCurrency: USDT"
}
if (!account[baseCurrency] || !account[quoteCurrency]) {
cancelAll(exchange)
var acc = _C(exchange.GetAccount)
account[baseCurrency] = acc.Stocks
account[quoteCurrency] = acc.Balance
}
// Initialize chart-related data
lastBarTime[symbol] = 0
arrChartConfig.push(createChartConfig(symbol, arrEma1Periods[index], arrEma2Periods[index]))
})
if (_G("initAccount")) {
initAccount = _G("initAccount")
Log("Restore initial account records", initAccount)
} else {
// Initialize the initAccount variable with the current asset information
_.each(account, function(val, key) {
initAccount[key] = val
})
}
Log("account:", account, "initAccount:", initAccount) // Print asset information
// Initialize the chart object
var chart = Chart(arrChartConfig)
// Chart reset
chart.reset()
// Strategy main loop logic
while (true) {
// Iterate through all varieties and execute the double-EMA logic one by one
_.each(arrSymbols, function(symbol, index) {
exchange.SetCurrency(symbol) // Switch the trading pair to the trading pair of symbol string record
var arrCurrencyName = symbol.split("_") // Split the trading pairs with the "_" symbol
var baseCurrency = arrCurrencyName[0] // String for trading currencies
var quoteCurrency = arrCurrencyName[1] // String for denominated currency
// Obtain the EMA parameters of the current trading pair according to the index
var ema1Period = parseFloat(arrEma1Periods[index])
var ema2Period = parseFloat(arrEma2Periods[index])
var amount = parseFloat(arrAmounts[index])
// Obtain the K-line data of the current trading pair
var r = exchange.GetRecords()
if (!r || r.length < Math.max(ema1Period, ema2Period)) { // Return directly if K-line length is insufficient
Sleep(1000)
return
}
var currBarTime = r[r.length - 1].Time // Record the current BAR timestamp
lastPrices[symbol] = r[r.length - 1].Close // Record the latest current price
var ema1 = TA.EMA(r, ema1Period) // Calculate EMA indicators
var ema2 = TA.EMA(r, ema2Period) // Calculate EMA indicators
if (ema1.length < 3 || ema2.length < 3) { // The length of EMA indicator array is too short, return directly
Sleep(1000)
return
}
var ema1Last2 = ema1[ema1.length - 2] // EMA on the penultimate BAR
var ema1Last3 = ema1[ema1.length - 3] // EMA on the third from the last BAR
var ema2Last2 = ema2[ema2.length - 2]
var ema2Last3 = ema2[ema2.length - 3]
// Write data to the chart
var klineIndex = index + 2 * index
// Iterate through the K-line data
for (var i = 0 ; i < r.length ; i++) {
if (r[i].Time == lastBarTime[symbol]) { // Draw the chart, update the current BAR and indicators
// update
chart.add(klineIndex, [r[i].Time, r[i].Open, r[i].High, r[i].Low, r[i].Close], -1)
chart.add(klineIndex + 1, [r[i].Time, ema1[i]], -1)
chart.add(klineIndex + 2, [r[i].Time, ema2[i]], -1)
} else if (r[i].Time > lastBarTime[symbol]) { // Draw the charts, add BARs and indicators
// add
lastBarTime[symbol] = r[i].Time // Update timestamp
chart.add(klineIndex, [r[i].Time, r[i].Open, r[i].High, r[i].Low, r[i].Close])
chart.add(klineIndex + 1, [r[i].Time, ema1[i]])
chart.add(klineIndex + 2, [r[i].Time, ema2[i]])
}
}
if (ema1Last3 < ema2Last3 && ema1Last2 > ema2Last2 && currTradeMsg[symbol] != currBarTime) {
// Golden cross
var depth = exchange.GetDepth() // Obtain the depth data of current order book
var price = depth.Asks[Math.min(takeLevel, depth.Asks.length)].Price // Take the 10th grade price, taker
if (depth && price * amount <= account[quoteCurrency]) { // Obtain deep data normally with enough assets to place an order
exchange.Buy(price, amount, ema1Last3, ema2Last3, ema1Last2, ema2Last2) // Place a buy order
cancelAll(exchange) // Cancel all makers
var acc = _C(exchange.GetAccount) // Obtain account asset information
if (acc.Stocks != account[baseCurrency]) { // Detect changes in account assets
account[baseCurrency] = acc.Stocks // Update assets
account[quoteCurrency] = acc.Balance // Update assets
currTradeMsg[symbol] = currBarTime // Record that the current BAR has been traded
_G("currTradeMsg", currTradeMsg) // Persistent records
var profit = getProfit(account, initAccount, lastPrices) // Calculate profits
if (profit) {
LogProfit(profit, account, initAccount) // Print profits
}
}
}
} else if (ema1Last3 > ema2Last3 && ema1Last2 < ema2Last2 && currTradeMsg[symbol] != currBarTime) {
// dead cross
var depth = exchange.GetDepth()
var price = depth.Bids[Math.min(takeLevel, depth.Bids.length)].Price
if (depth && amount <= account[baseCurrency]) {
exchange.Sell(price, amount, ema1Last3, ema2Last3, ema1Last2, ema2Last2)
cancelAll(exchange)
var acc = _C(exchange.GetAccount)
if (acc.Stocks != account[baseCurrency]) {
account[baseCurrency] = acc.Stocks
account[quoteCurrency] = acc.Balance
currTradeMsg[symbol] = currBarTime
_G("currTradeMsg", currTradeMsg)
var profit = getProfit(account, initAccount, lastPrices)
if (profit) {
LogProfit(profit, account, initAccount)
}
}
}
}
Sleep(1000)
})
// Table variables in the status bar
var tbl = {
type : "table",
title : "Account Information",
cols : [],
rows : []
}
// Write data into the status bar table structure
tbl.cols.push("--")
tbl.rows.push(["initial"])
tbl.rows.push(["current"])
_.each(account, function(val, key) {
if (typeof(initAccount[key]) == "number") {
tbl.cols.push(key)
tbl.rows[0].push(initAccount[key]) // initial
tbl.rows[1].push(val) // current
}
})
// Show status bar table
LogStatus(_D(), "\n", "profit:", getProfit(account, initAccount, lastPrices), "\n", "`" + JSON.stringify(tbl) + "`")
}
}
ETH, LTC, ETC는 EMA의 골든 크로스와 데드 크로스에 따라 트리거되고 거래가 이루어졌다는 것을 알 수 있습니다.
우리는 또한 시뮬레이션 로봇을 테스트를 위해 가져갈 수 있습니다.
전략 소스 코드:https://www.fmz.com/strategy/333783
이 전략은 배트테스팅, 학습 전략 설계에만 사용되며 실제 봇에서는 조심스럽게 사용해야 합니다.