仮想通貨スポット・マルチ・シンボル・ダブル・ムービング・平均戦略 (教学)

作者: リン・ハーンニナバダス作成日:2022-04-07 16:14:35 更新日:2022-04-08 09:13:58 更新日:2022-04-08 更新日:2022-04-08 09:13:58 更新日:2022-04-08 更新日:2022-04-08 09:13:58 更新日:2020-04-08 更新日:2020-04-08 09:13:58 更新日:2020-04-08 更新日:2020-04-08 09:13:58 更新日:2020-04-08 更新日:2018-04-08 更新日:2018-04-08

仮想通貨スポット・マルチ・シンボル・ダブル・ムービング・平均戦略 (教学)

フォーラムのユーザーからの要求により,設計基準として多シンボルのデュアル移動平均戦略を希望しているため,今日の共有では多シンボルのデュアル移動平均戦略が実装されます. 戦略の理解と学習を容易にするために,戦略コードにコメントが書き込まれ,プログラムおよび定量取引のより多くの新しい学生が戦略を迅速に開始できるようになります.

戦略 的 な 考え方

二重移動平均戦略の論理は非常にシンプルである.つまり,移動平均は2つある.短い期間を持つ移動平均 (fast line) と,長い期間を持つ移動平均 (slow line).両線が黄色の交差点を持つとき (速い線が下の方からスローラインを横切る),ロングを購入し,両線がデッドクロスを持つとき (速い線が下の方からスローラインを横切る),ショート販売する.移動平均のために,EMAを使用する.

戦略は複数のシンボルのために設計されなければなりません. そのため,異なるシンボルのパラメータは異なるかもしれません (異なるシンボルは異なる移動平均パラメータを使用します).

img

パラメータは文字列の形式で設計され,各パラメータは逗子で分割される.この文字列は,戦略が実行開始時に解析され,各シンボル (取引ペア) の実行論理とマッチされます.戦略投票は,すべてのシンボル,取引条件のトリガー,チャートプリントの市場引数を検出します.すべてのシンボルが1回投票した後,データはアグリゲートされ,テーブル情報はステータスバーに表示されます.

この戦略は非常にシンプルで 初心者にも適しています 200行以上しかありません

戦略コード

// function effect: to cancel all pending orders 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)
    }
}

// function effect: to calculate the real-time profit and loss  
function getProfit(account, initAccount, lastPrices) {
    // account indicates the current account information; initAccount is the initial account information; lastPrices is the the latest prices of all current symbols 
    var sum = 0
    _.each(account, function(val, key) {
        // traverse the current total assets, and calculate asset currency (except USDT) difference and amount difference 
        if (key != "USDT" && typeof(initAccount[key]) == "number" && lastPrices[key + "_USDT"]) {
            sum += (account[key] - initAccount[key]) * lastPrices[key + "_USDT"]
        }        
    })
    // return the asset profit and loss calculated by the current price 
    return account["USDT"] - initAccount["USDT"] + sum
}

// function effect: to generate chart configuration 
function createChartConfig(symbol, ema1Period, ema2Period) {
    // symbol indicates trading pair; ema1Period indicates the first EMA period; ema2Period indicates the second EMA period 
    var chart = {                                        
        __isStock: true,    
        extension: {
                layout: 'single', 
                height: 600, 
        },
        title : { text : symbol},                       
        xAxis: { type: 'datetime'},           
        series : [                                          
            {                                      
                type: 'candlestick',    // K-line date 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)            // vacuum all persistently recorded data  
        LogReset(1)         // vacuum all logs 
        LogProfitReset()    // vacuum all profit logs 
        LogVacuum()         // release the resource occupied by the bot database 
        Log("reset all data", "#FF0000")   // print information 
    }
    
    // parse parameters 
    var arrSymbols = symbols.split(",")             // use comma to split the trading symbol strings 
    var arrEma1Periods = ema1Periods.split(",")     // split the string of the first EMA parameter
    var arrEma2Periods = ema2Periods.split(",")     // split the string of the second EMA parameter
    var arrAmounts = orderAmounts.split(",")        // split the order amount of each symbol
    var account = {}                                // the variable used to record the current asset information 
    var initAccount = {}                            // the variable used to record the initial asset information 
    var currTradeMsg = {}                           // the variable used to record whether the current BAR is executed 
    var lastPrices = {}                             // the variable used to record the latest price of the monitored symbol 
    var lastBarTime = {}                            // the variable used to record the time of the latest BAR, to judge the BAR update during plotting
    var arrChartConfig = []                         // the variable used to record the chart configuration information, to plot  

    if (_G("currTradeMsg")) {                       // for example, when restart, recover currTradeMsg data 
        currTradeMsg = _G("currTradeMsg")
        Log("recover GetRecords", 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 the related data of chart 
        lastBarTime[symbol] = 0
        arrChartConfig.push(createChartConfig(symbol, arrEma1Periods[index], arrEma2Periods[index]))
    })
    if (_G("initAccount")) {
        initAccount = _G("initAccount")
        Log("recover initial account information", initAccount)
    } else {
        // use the current asset information to initialize initAccount (variable)
        _.each(account, function(val, key) {
            initAccount[key] = val
        })
    }
    Log("account:", account, "initAccount:", initAccount)   // print asset information 

    // initialize the chart objects 
    var chart = Chart(arrChartConfig)
    // reset chart 
    chart.reset()
        
    // strategy logic of the main loop 
    while (true) {
        // traverse all symbols, and execute the dual moving average logic one  by one 
        _.each(arrSymbols, function(symbol, index) {
            exchange.SetCurrency(symbol)               // switch the trading pair to the trading pair recorded by by symbol string 
            var arrCurrencyName = symbol.split("_")    // split trading pairs by "_" 
            var baseCurrency = arrCurrencyName[0]      // string of base currency
            var quoteCurrency = arrCurrencyName[1]     // string of quote currency

            // according to index, obtain the EMA paramater of the current trading pair 
            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)) {  // when the length of K-line is not long enough, return directly 
                Sleep(1000)
                return 
            }
            var currBarTime = r[r.length - 1].Time         // record the current BAR timestamp 
            lastPrices[symbol] = r[r.length - 1].Close     //  record the current latest price 

            var ema1 = TA.EMA(r, ema1Period)    // calculate EMA indicator
            var ema2 = TA.EMA(r, ema2Period)    // calculate EMA indicator
            if (ema1.length < 3 || ema2.length < 3) {    // when the length of EMA indicator array is too short, return derectly 
                Sleep(1000)
                return 
            }
            var ema1Last2 = ema1[ema1.length - 2]   // EMA on the second last BAR 
            var ema1Last3 = ema1[ema1.length - 3]   // EMA on the third last BAR
            var ema2Last2 = ema2[ema2.length - 2]
            var ema2Last3 = ema2[ema2.length - 3]

            // write the chart data 
            var klineIndex = index + 2 * index
            // traverse k-line data 
            for (var i = 0 ; i < r.length ; i++) {
                if (r[i].Time == lastBarTime[symbol]) {         // plot; update the current BAR and its indicator 
                    // 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]) {   // plot; add BAR and its indicator 
                    // add
                    lastBarTime[symbol] = r[i].Time             // update the 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 the current order book 
                var price = depth.Asks[Math.min(takeLevel, depth.Asks.length)].Price   // select the 10th level price; taker 
                if (depth && price * amount <= account[quoteCurrency]) {   // obtain that the depth data is normal, and the assets are enough to place an order 
                    exchange.Buy(price, amount, ema1Last3, ema2Last3, ema1Last2, ema2Last2)   // maker; buy 
                    cancelAll(exchange)     // cancel all pending orders 
                    var acc = _C(exchange.GetAccount)   // obtain the account asset information 
                    if (acc.Stocks != account[baseCurrency]) {  // detect the account assets changed 
                        account[baseCurrency] = acc.Stocks      // update assets
                        account[quoteCurrency] = acc.Balance    // update assets
                        currTradeMsg[symbol] = currBarTime      // record the current BAR has been executed 
                        _G("currTradeMsg", currTradeMsg)        // persistently record  
                        var profit = getProfit(account, initAccount, lastPrices)  // calculate profit
                        if (profit) {
                            LogProfit(profit, account, initAccount)    // print profit 
                        }
                    }
                }
            } else if (ema1Last3 > ema2Last3 && ema1Last2 < ema2Last2 && currTradeMsg[symbol] != currBarTime) {
                // death 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)
        })

        // variables in the table of status bar 
        var tbl = {
            type : "table", 
            title : "account information",
            cols : [], 
            rows : []
        }
        // write the data in the table structure of status bar 
        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 
            }            
        })
        // display the status bar table 
        LogStatus(_D(), "\n", "profit:", getProfit(account, initAccount, lastPrices), "\n", "`" + JSON.stringify(tbl) + "`")
    }
}

戦略 バックテスト

img

img

img

ETH,LTC,ETCは全て 移動平均値の金十字と死十字のトリガーに従って取引していました

img

ロボットシミュレーションを テストすることもできます

戦略のソースコード:https://www.fmz.com/strategy/333783

この戦略はバックテストや戦略設計学習にのみ使用されますので,ボットでは慎重に使用してください.


もっと