বাইডাইরেকশনাল মুভিং এভারেজ রিভার্সন ট্রেডিং কৌশল হল একটি পরিমাণগত ট্রেডিং কৌশল যা দামের গড় রিভার্সন নীতি ব্যবহার করে তৈরি করা হয়েছে। এই কৌশলটি একাধিক গ্রুপের চলমান গড় স্থাপন করে দামের বিপরীতমুখী সুযোগগুলি ধরার জন্য, গড়ের কাছ থেকে কিছুটা বিচ্যুতির পরে খেলায় প্রবেশ করে এবং গড়ের দিকে ফিরে আসার জন্য অপেক্ষা করে।
এই কৌশলটি মূলত মূল্যের গড় প্রত্যাবর্তন তত্ত্বের উপর ভিত্তি করে। এটি বিশ্বাস করে যে দাম সর্বদা একটি গড় মানের ঘূর্ণনকে ঘিরে থাকে, যখন দাম গড় মান থেকে গুরুতরভাবে বিচ্যুত হয় তখন গড়ের দিকে ফিরে যাওয়ার সম্ভাবনা বেশি থাকে। বিশেষত, এই কৌশলটি একই সাথে তিনটি গড় লাইন সেট করেঃ খোলার গড় লাইন, খোলার গড় লাইন এবং সীমাবদ্ধ গড় লাইন। যখন দাম খোলার গড় লাইনটি স্পর্শ করে, তখন প্রতিযোগিতামূলক ওভার বা শূন্য পজিশন খোলা হয়। যখন দাম খোলার গড় লাইনটি স্পর্শ করে, তখন পূর্ববর্তী পজিশনটি সমতল করা হয়। অবশেষে, যদি দাম কোনও প্রত্যাবর্তন না করে চলতে থাকে তবে সীমাবদ্ধ গড় লাইনটি ক্ষতি নিয়ন্ত্রণ করতে পারে।
কোড লজিকের দিক থেকে দেখা যায় যে, ওপেন পজিশনের গড়রেখাটি লম্বা লাইন এবং সংক্ষিপ্ত লাইন দ্বারা বিভক্ত। দামের সাথে তাদের মধ্যে বিচ্যুতির মাত্রা পজিশনের আকার নির্ধারণ করে। এছাড়াও, পজিশনের গড়রেখাটি একটি পৃথক গড়রেখা যা পজিশনের সময় নির্ধারণের জন্য ব্যবহৃত হয়। যখন দাম এই গড়রেখায় চলে যায় তখন পজিশনটি সমতল করা হয়।
দ্বি-মুখী সমান্তরাল প্রত্যাবর্তন কৌশলটির প্রধান সুবিধাগুলি হলঃ
এই কৌশলটি কম ওঠানামা, দামের ওঠানামার ছোট পরিসরের জাতের জন্য প্রযোজ্য, বিশেষত যে জাতগুলি পুনরুদ্ধারের পর্যায়ে প্রবেশ করে। এটি মূল্যের অস্থায়ী বিপর্যয়ের সুযোগকে কার্যকরভাবে ক্যাপচার করতে পারে। একই সাথে, এর ঝুঁকি নিয়ন্ত্রণ ব্যবস্থাগুলিও বেশ পরিপূর্ণ, এমনকি যদি দাম ফিরে না আসে তবে ক্ষতি নিয়ন্ত্রণ করতে পারে।
কিন্তু এই দুই দিকের সমান্তরাল প্রত্যাবর্তনের কিছু ঝুঁকি রয়েছেঃ
উপরোক্ত ঝুঁকির জন্য, নিম্নলিখিত দিকগুলি থেকে অপ্টিমাইজেশন করা যেতে পারেঃ
এই কৌশলটি আরও অনেক উন্নতি করতে পারে, বিশেষ করে নিম্নলিখিত দিকগুলি থেকেঃ
দ্বি-মুখী গড়রেখা প্রত্যাবর্তন ট্রেডিং কৌশলটি মুভিং গড়রেখার থেকে দামের বিচ্যুতির পরে প্রত্যাবর্তনের সুযোগগুলি ক্যাপচার করে মুনাফা অর্জন করে। এটি কার্যকরভাবে ঝুঁকি নিয়ন্ত্রণ করে এবং প্যারামিটার অপ্টিমাইজেশনের মাধ্যমে আরও ভাল রিটার্ন অর্জন করতে পারে। যদিও এই কৌশলটির কিছু ঝুঁকিও রয়েছে, তবে এটি পজিশন খোলার লজিককে উন্নত করে, পজিশন আকার হ্রাস করে এবং অন্যান্য পদ্ধতির মাধ্যমে নিয়ন্ত্রণ করা যেতে পারে। এই কৌশলটি সহজেই বোঝা যায় এবং এটি আরও গবেষণা এবং অপ্টিমাইজেশনের জন্য পরিমাণযুক্ত ব্যবসায়ীদের জন্য উপযুক্ত।
/*backtest
start: 2023-12-15 00:00:00
end: 2024-01-14 00:00:00
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/
//@version=5
strategy(title = "hamster-bot MRS 2", overlay = true, default_qty_type = strategy.percent_of_equity, initial_capital = 100, default_qty_value = 30, pyramiding = 1, commission_value = 0.1, backtest_fill_limits_assumption = 1)
info_options = "Options"
on_close = input(false, title = "Entry on close", inline=info_options, group=info_options)
OFFS = input.int(0, minval = 0, maxval = 1, title = "| Offset View", inline=info_options, group=info_options)
trade_offset = input.int(0, minval = 0, maxval = 1, title = "Trade", inline=info_options, group=info_options)
use_kalman_filter = input.bool(false, title="Use Kalman filter", group=info_options)
//MA Opening
info_opening = "MA Opening Long"
maopeningtyp_l = input.string("SMA", title="Type", options=["SMA", "EMA", "TEMA", "DEMA", "ZLEMA", "WMA", "Hma", "Thma", "Ehma", "H", "L", "DMA"], title = "", inline=info_opening, group=info_opening)
maopeningsrc_l = input.source(ohlc4, title = "", inline=info_opening, group=info_opening)
maopeninglen_l = input.int(3, minval = 1, title = "", inline=info_opening, group=info_opening)
long1on = input(true, title = "", inline = "long1")
long1shift = input.float(0.96, step = 0.005, title = "Long", inline = "long1")
long1lot = input.int(10, minval = 0, maxval = 10000, step = 10, title = "Lot 1", inline = "long1")
info_opening_s = "MA Opening Short"
maopeningtyp_s = input.string("SMA", title="Type", options=["SMA", "EMA", "TEMA", "DEMA", "ZLEMA", "WMA", "Hma", "Thma", "Ehma", "H", "L", "DMA"], title = "", inline=info_opening_s, group=info_opening_s)
maopeningsrc_s = input.source(ohlc4, title = "", inline=info_opening_s, group=info_opening_s)
maopeninglen_s = input.int(3, minval = 1, title = "", inline=info_opening_s, group=info_opening_s)
short1on = input(true, title = "", inline = "short1")
short1shift = input.float(1.04, step = 0.005, title = "short", inline = "short1")
short1lot = input.int(10, minval = 0, maxval = 10000, step = 10, title = "Lot 1", inline = "short1")
//MA Closing
info_closing = "MA Closing"
maclosingtyp = input.string("SMA", title="Type", options=["SMA", "EMA", "TEMA", "DEMA", "ZLEMA", "WMA", "Hma", "Thma", "Ehma", "H", "L", "DMA"], title = "", inline=info_closing, group=info_closing)
maclosingsrc = input.source(ohlc4, title = "", inline=info_closing, group=info_closing)
maclosinglen = input.int(3, minval = 1, maxval = 200, title = "", inline=info_closing, group=info_closing)
maclosingmul = input.float(1, step = 0.005, title = "mul", inline=info_closing, group=info_closing)
startTime = input(timestamp("01 Jan 2010 00:00 +0000"), "Start date", inline = "period")
finalTime = input(timestamp("31 Dec 2030 23:59 +0000"), "Final date", inline = "period")
HMA(_src, _length) => ta.wma(2 * ta.wma(_src, _length / 2) - ta.wma(_src, _length), math.round(math.sqrt(_length)))
EHMA(_src, _length) => ta.ema(2 * ta.ema(_src, _length / 2) - ta.ema(_src, _length), math.round(math.sqrt(_length)))
THMA(_src, _length) => ta.wma(ta.wma(_src,_length / 3) * 3 - ta.wma(_src, _length / 2) - ta.wma(_src, _length), _length)
tema(sec, length)=>
tema1= ta.ema(sec, length)
tema2= ta.ema(tema1, length)
tema3= ta.ema(tema2, length)
tema_r = 3*tema1-3*tema2+tema3
donchian(len) => math.avg(ta.lowest(len), ta.highest(len))
ATR_func(_src, _len)=>
atrLow = low - ta.atr(_len)
trailAtrLow = atrLow
trailAtrLow := na(trailAtrLow[1]) ? trailAtrLow : atrLow >= trailAtrLow[1] ? atrLow : trailAtrLow[1]
supportHit = _src <= trailAtrLow
trailAtrLow := supportHit ? atrLow : trailAtrLow
trailAtrLow
f_dema(src, len)=>
EMA1 = ta.ema(src, len)
EMA2 = ta.ema(EMA1, len)
DEMA = (2*EMA1)-EMA2
f_zlema(src, period) =>
lag = math.round((period - 1) / 2)
ema_data = src + (src - src[lag])
zl= ta.ema(ema_data, period)
f_kalman_filter(src) =>
float value1= na
float value2 = na
value1 := 0.2 * (src - src[1]) + 0.8 * nz(value1[1])
value2 := 0.1 * (ta.tr) + 0.8 * nz(value2[1])
lambda = math.abs(value1 / value2)
alpha = (-math.pow(lambda, 2) + math.sqrt(math.pow(lambda, 4) + 16 * math.pow(lambda, 2)))/8
value3 = float(na)
value3 := alpha * src + (1 - alpha) * nz(value3[1])
//SWITCH
ma_func(modeSwitch, src, len, use_k_f=true) =>
modeSwitch == "SMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.sma(src, len)) : ta.sma(src, len) :
modeSwitch == "RMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.rma(src, len)) : ta.rma(src, len) :
modeSwitch == "EMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.ema(src, len)) : ta.ema(src, len) :
modeSwitch == "TEMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(tema(src, len)) : tema(src, len):
modeSwitch == "DEMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(f_dema(src, len)) : f_dema(src, len):
modeSwitch == "ZLEMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(f_zlema(src, len)) : f_zlema(src, len):
modeSwitch == "WMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.wma(src, len)) : ta.wma(src, len):
modeSwitch == "VWMA" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.vwma(src, len)) : ta.vwma(src, len):
modeSwitch == "Hma" ? use_kalman_filter and use_k_f ? f_kalman_filter(HMA(src, len)) : HMA(src, len):
modeSwitch == "Ehma" ? use_kalman_filter and use_k_f ? f_kalman_filter(EHMA(src, len)) : EHMA(src, len):
modeSwitch == "Thma" ? use_kalman_filter and use_k_f ? f_kalman_filter(THMA(src, len/2)) : THMA(src, len/2):
modeSwitch == "ATR" ? use_kalman_filter and use_k_f ? f_kalman_filter(ATR_func(src, len)): ATR_func(src, len) :
modeSwitch == "L" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.lowest(len)): ta.lowest(len) :
modeSwitch == "H" ? use_kalman_filter and use_k_f ? f_kalman_filter(ta.highest(len)): ta.highest(len) :
modeSwitch == "DMA" ? donchian(len) : na
//Var
sum = 0.0
maopening_l = 0.0
maopening_s = 0.0
maclosing = 0.0
pos = strategy.position_size
p = 0.0
p := pos == 0 ? (strategy.equity / 100) / close : p[1]
truetime = true
loss = 0.0
maxloss = 0.0
equity = 0.0
//MA Opening
maopening_l := ma_func(maopeningtyp_l, maopeningsrc_l, maopeninglen_l)
maopening_s := ma_func(maopeningtyp_s, maopeningsrc_s, maopeninglen_s)
//MA Closing
maclosing := ma_func(maclosingtyp, maclosingsrc, maclosinglen) * maclosingmul
long1 = long1on == false ? 0 : long1shift == 0 ? 0 : long1lot == 0 ? 0 : maopening_l == 0 ? 0 : maopening_l * long1shift
short1 = short1on == false ? 0 : short1shift == 0 ? 0 : short1lot == 0 ? 0 : maopening_s == 0 ? 0 : maopening_s * short1shift
//Colors
long1col = long1 == 0 ? na : color.green
short1col = short1 == 0 ? na : color.red
//Lines
// plot(maopening_l, offset = OFFS, color = color.new(color.green, 50))
// plot(maopening_s, offset = OFFS, color = color.new(color.red, 50))
plot(maclosing, offset = OFFS, color = color.fuchsia)
long1line = long1 == 0 ? close : long1
short1line = short1 == 0 ? close : short1
plot(long1line, offset = OFFS, color = long1col)
plot(short1line, offset = OFFS, color = short1col)
//Lots
lotlong1 = p * long1lot
lotshort1 = p * short1lot
//Entry
if truetime
//Long
sum := 0
strategy.entry("L", strategy.long, lotlong1, limit = on_close ? na : long1, when = long1 > 0 and pos <= sum and (on_close ? close <= long1[trade_offset] : true))
sum := lotlong1
//Short
sum := 0
pos := -1 * pos
strategy.entry("S", strategy.short, lotshort1, limit = on_close ? na : short1, when = short1 > 0 and pos <= sum and (on_close ? close >= short1[trade_offset] : true))
sum := lotshort1
strategy.exit("Exit", na, limit = maclosing)
if time > finalTime
strategy.close_all()