
Chiến lược này là một chiến lược giao dịch định lượng thực nghiệm, kết hợp các chỉ số trung bình di chuyển và thuật toán kNN của máy học để tạo ra tín hiệu giao dịch. Chiến lược này sử dụng giao thoa của các đường trung bình VWMA của hai chu kỳ khác nhau để xác định hướng xu hướng và kết hợp hai chỉ số MFI và ADX để lọc tín hiệu thông qua thuật toán kNN để tăng độ tin cậy tín hiệu.
Chỉ số cốt lõi của chiến lược này là đường trung bình VWMA với hai tham số khác nhau, đường nhanh và đường chậm. Một tín hiệu mua được tạo ra khi đường nhanh đi qua đường chậm và một tín hiệu bán khi đường nhanh đi qua đường chậm. Ngoài ra, chiến lược này đã giới thiệu hai chỉ số phụ trợ MFI và ADX để đánh giá độ tin cậy của tín hiệu trong điều kiện thị trường hiện tại thông qua thuật toán phân loại KNN.
Ý tưởng của thuật toán kNN là so sánh dữ liệu mới với dữ liệu lịch sử, đánh giá kết quả tương ứng với dữ liệu lịch sử k gần nhất, và phân loại theo cách bỏ phiếu đa số dựa trên kết quả lịch sử k này. Chiến lược này sử dụng MFI và ADX làm hai tham số đầu vào của thuật toán kNN để đánh giá xu hướng giá lịch sử khi kết hợp hai chỉ số này (lên hoặc xuống) để lọc tín hiệu hiện tại và cải thiện chất lượng tín hiệu.
Phản ứng:
Chiến lược này có thể được tối ưu hóa rất nhiều:
Các nhà nghiên cứu cho rằng việc đưa ra nhiều chỉ số hơn và các thuật toán học máy có thể làm tăng thêm sự ổn định và lợi nhuận của các chiến lược.
Chiến lược này là một chiến lược giao dịch định lượng thực nghiệm dựa trên chỉ số đường trung bình VWMA và thuật toán học máy của KNN. Nó có khả năng theo dõi xu hướng mạnh mẽ, đồng thời có khả năng lọc tín hiệu thông qua học máy.
/*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)