Это экспериментальная количественная стратегия торговли, которая сочетает в себе индикаторы скользящей средней и алгоритмы машинного обучения kNN для генерации торговых сигналов.
Основными показателями этой стратегии являются две линии VWMA с различными параметрами, а именно быстрая линия и медленная линия. Когда быстрая линия пересекает поверх медленной линии, генерируется сигнал покупки. Когда быстрая линия пересекает ниже медленной линии, генерируется сигнал продажи. Кроме того, эта стратегия вводит два вспомогательных индикатора, MFI и ADX, для оценки надежности текущего сигнала в текущих рыночных условиях через алгоритм классификации kNN.
Идея алгоритма kNN заключается в сравнении новых данных с историческими данными, чтобы определить результаты, соответствующие k наиболее похожим историческим данным, и классифицировать на основе большинства голосов этих k исторических результатов.
Уменьшение последствий:
Существует большое пространство для оптимизации этой стратегии:
Внедрение большего количества индикаторов и алгоритмов машинного обучения может еще больше улучшить стабильность и рентабельность стратегии.
Это экспериментальная количественная торговая стратегия, основанная на индикаторах VWMA и алгоритмах машинного обучения kNN. Она имеет преимущество сильной способности следовать за трендом при фильтрации сигналов с помощью машинного обучения. Стратегия имеет большое пространство для расширения, внедряя больше функций и алгоритмов оптимизации для лучших результатов.
/*backtest start: 2023-11-21 00:00:00 end: 2023-12-21 00:00:00 period: 1h basePeriod: 15m exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}] */ // This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © lastguru //@version=4 strategy(title="VWMA with kNN Machine Learning: MFI/ADX", shorttitle="VWMA + kNN: MFI/ADX", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=100) ///////// // kNN // ///////// // Define storage arrays for: parameter 1, parameter 2, price, result (up = 1; down = -1) var knn1 = array.new_float(1, 0) var knn2 = array.new_float(1, 0) var knnp = array.new_float(1, 0) var knnr = array.new_float(1, 0) // Store the previous trade; buffer the current one until results are in _knnStore (p1, p2, src) => var prevp1 = 0.0 var prevp2 = 0.0 var prevsrc = 0.0 array.push(knn1, prevp1) array.push(knn2, prevp2) array.push(knnp, prevsrc) array.push(knnr, src >= prevsrc ? 1 : -1) prevp1 := p1 prevp2 := p2 prevsrc := src // Sort two arrays (MUST be of the same size) based on the first. // In other words, when an element in the first is moved, the element in the second moves as well. _knnGet(arr1, arr2, k) => sarr = array.copy(arr1) array.sort(sarr) ss = array.slice(sarr, 0, min(k, array.size(sarr))) m = array.max(ss) out = array.new_float(0) for i = 0 to array.size(arr1) - 1 if (array.get(arr1, i) <= m) array.push(out, array.get(arr2, i)) out // Create a distance array from the two given parameters _knnDistance(p1, p2) => dist = array.new_float(0) n = array.size(knn1) - 1 for i = 0 to n d = sqrt( pow(p1 - array.get(knn1, i), 2) + pow(p2 - array.get(knn2, i), 2) ) array.push(dist, d) dist // Make a prediction, finding k nearest neighbours _knn(p1, p2, k) => slice = _knnGet(_knnDistance(p1, p2), array.copy(knnr), k) knn = array.sum(slice) //////////// // Inputs // //////////// SRC = input(title="Source", type=input.source, defval=open) FAST = input(title="Fast Length", type=input.integer, defval=13) SLOW = input(title="Slow Length", type=input.integer, defval=19) FILTER = input(title="Filter Length", type=input.integer, defval=13) SMOOTH = input(title="Filter Smoothing", type=input.integer, defval=6) KNN = input(title="kNN nearest neighbors (k)", type=input.integer, defval=23) BACKGROUND = input(false,title = "Draw background") //////// // MA // //////// fastMA = vwma(SRC, FAST) slowMA = vwma(SRC, SLOW) ///////// // DMI // ///////// // Wilder's Smoothing (Running Moving Average) _rma(src, length) => out = 0.0 out := ((length - 1) * nz(out[1]) + src) / length // DMI (Directional Movement Index) _dmi (len, smooth) => up = change(high) down = -change(low) plusDM = na(up) ? na : (up > down and up > 0 ? up : 0) minusDM = na(down) ? na : (down > up and down > 0 ? down : 0) trur = _rma(tr, len) plus = fixnan(100 * _rma(plusDM, len) / trur) minus = fixnan(100 * _rma(minusDM, len) / trur) sum = plus + minus adx = 100 * _rma(abs(plus - minus) / (sum == 0 ? 1 : sum), smooth) [plus, minus, adx] [diplus, diminus, adx] = _dmi(FILTER, SMOOTH) ///////// // MFI // ///////// // common RSI function _rsi(upper, lower) => if lower == 0 100 if upper == 0 0 100.0 - (100.0 / (1.0 + upper / lower)) mfiUp = sum(volume * (change(ohlc4) <= 0 ? 0 : ohlc4), FILTER) mfiDown = sum(volume * (change(ohlc4) >= 0 ? 0 : ohlc4), FILTER) mfi = _rsi(mfiUp, mfiDown) //////////// // Filter // //////////// longCondition = crossover(fastMA, slowMA) shortCondition = crossunder(fastMA, slowMA) if (longCondition or shortCondition) _knnStore(adx, mfi, SRC) filter = _knn(adx, mfi, KNN) ///////////// // Actions // ///////////// bgcolor(BACKGROUND ? filter >= 0 ? color.green : color.red : na) plot(fastMA, color=color.red) plot(slowMA, color=color.green) if (longCondition and filter >= 0) strategy.entry("Long", strategy.long) if (shortCondition and filter < 0) strategy.entry("Short", strategy.short)