Enhanced Fish Net Strategy

Author: ChaoZhang, Date: 2023-09-12 10:49:00
Tags:

改良型渔网策略

该策略对经典的渔网策略进行了改进,加入了买卖信号阈值、移动止损等功能,形成较为完整的趋势追踪体系。

渔网策略通过计算价格的力度中心来判断市场趋势,力度中心反映了价格和成交量的关系。当力度中心上升时表示多头力量增强,下降时表示空头力量增强,因此可以据此产生交易信号。

计算力度中心的关键在于价格与时间的关系。简单来说,最近发生的价格变动影响趋势判断的权重更大,久远的价格变动权重更小。因此计算时,乘以一个随时间衰减的权重。这样高位发生的交易对总体判断影响更大。

但原始的渔网策略只根据力度中心曲线的方向判断多空,很容易在横盘时被套牢。这次改进加入了确定的买卖信号阈值,只有在力度中心超过一定幅度时才发出信号,这样可以过滤掉许多噪音信号。

此外,改进版本实现了移动止损和固定止损相结合的出场机制。进入趋势后,移动止损可以随行情的推移不断调整,实现流动的风险控制。而固定止损则可以更加可靠地防止突发事件造成的损失。

当然,力度中心指标对复杂行情的判断力较弱,移动止损在设定不当时也可能被突破,这需要交易者保持警惕,适时优化参数。但总的来说,这套改进型渔网策略机制更加完备,可以产生较好的稳定收益。


/*backtest
start: 2023-09-04 00:00:00
end: 2023-09-11 00:00:00
period: 30m
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=3
// Copyright nilux: https://www.tradingview.com/u/nilux/
// Based on the original of dasanc: https://www.tradingview.com/u/dasanc/

strategy("FSCG-TSSL", "FSCG-TSSL Mod Backtest", default_qty_type = strategy.percent_of_equity, default_qty_value = 100, initial_capital = 100000, slippage = 5)
Price = input.source(close, "Source")
Length = input(20,"Period")
transform = input("Inphase-Quadrature","Use Transform?",options=["Hilbert","Inphase-Quadrature","False"])
min = input(108,"Min. Period")
buyTreshold = input(-2.41, title = "Buy Treshold (-)", type = float, defval=-2.0, minval = -2.50, maxval = -0.01, step = 0.01)
sellTreshold = input(2.43, title = "Sell Treshold (+)", type = float, defval=2.0, minval = 0.01, maxval = 2.50, step = 0.01)

// === TSSL ===
fixedSL = input(title="SL Activation", defval=300)
trailSL = input(title="SL Trigger", defval=1)
fixedTP = input(title="TP Activation", defval=150)
trailTP = input(title="TP Trigger", defval=50)

// === BACKTEST RANGE ===
FromMonth = input(defval = 1, title = "From Month", minval = 1, maxval = 12)
FromDay   = input(defval = 1, title = "From Day", minval = 1, maxval = 31)
FromYear  = input(defval = 2019, title = "From Year", minval = 2015)
ToMonth   = input(defval = 1, title = "To Month", minval = 1, maxval = 12)
ToDay     = input(defval = 1, title = "To Day", minval = 1, maxval = 31)
ToYear    = input(defval = 9999, title = "To Year", minval = 2015)
start     = timestamp(FromYear, FromMonth, FromDay, 00, 00)
finish    = timestamp(ToYear, ToMonth, ToDay, 23, 59)
window()  => time >= start and time <= finish ? true : false

getIQ(src,min,max) =>
    PI = 3.14159265359
    P = src - src[7]
    lenIQ = 0.0
    lenC = 0.0
    imult = 0.635
    qmult = 0.338
    inphase = 0.0
    quadrature = 0.0
    re = 0.0
    im = 0.0
    deltaIQ = 0.0
    instIQ = 0.0
    V = 0.0
    
    inphase := 1.25*(P[4] - imult*P[2]) + imult*nz(inphase[3])
    quadrature := P[2] - qmult*P + qmult*nz(quadrature[2])
    re := 0.2*(inphase*inphase[1] + quadrature*quadrature[1]) + 0.8*nz(re[1])
    im := 0.2*(inphase*quadrature[1] - inphase[1]*quadrature) + 0.8*nz(im[1])
    if (re!= 0.0)
        deltaIQ := atan(im/re)
    for i=0 to max
        V := V + deltaIQ[i]
        if (V > 2*PI and instIQ == 0.0)
            instIQ := i
    if (instIQ == 0.0)
        instIQ := nz(instIQ[1])
    lenIQ := 0.25*instIQ + 0.75*nz(lenIQ[1],1)
    length = lenIQ<min ? min : lenIQ


getHT(src) =>
    Price = src
    Imult = .635
    Qmult = .338
    PI = 3.14159
    InPhase = 0.0
    Quadrature = 0.0
    Phase = 0.0
    DeltaPhase = 0.0
    InstPeriod = 0.0
    Period = 0.0
    Value4 = 0.0
    
    if(n > 5)
        //Detrend Price
        Value3 = Price - Price[7]
        //Compute InPhase and Quadrature components
        InPhase := 1.25*(Value3[4] - Imult*Value3[2]) + Imult*nz(InPhase[3])
        Quadrature := Value3[2] - Qmult*Value3 + Qmult*nz(Quadrature[2])
        //Use ArcTangent to compute the current phase
        if(abs(InPhase + InPhase[1]) > 0)
            Phase := 180/PI * atan(abs((Quadrature + Quadrature[1]) / (InPhase + InPhase[1])))
        //Resolve the ArcTangent ambiguity
        if(InPhase < 0 and Quadrature > 0)
            Phase := 180 - Phase
        if(InPhase < 0 and Quadrature < 0)
            Phase := 180 + Phase
        if(InPhase > 0 and Quadrature < 0)
            Phase := 360 - Phase
        //Compute a differential phase, resolve phase wraparound, and limit delta phase errors
        DeltaPhase := Phase[1] - Phase
        if(Phase[1] < 90 and Phase > 270)
            DeltaPhase := 360 + Phase[1] - Phase
        if(DeltaPhase < 1)
            DeltaPhase := 1
        if(DeltaPhase > 60)
            DeltaPhase := 60
        //Sum DeltaPhases to reach 360 degrees. The sum is the instantaneous period.
        for i = 0 to 50
            Value4 := Value4 + DeltaPhase[i]
            if(Value4 > 360 and InstPeriod == 0)
                InstPeriod := i
        //Resolve Instantaneous Period errors and smooth
        if(InstPeriod == 0)
            InstPeriod = nz(InstPeriod[1])
        Period := .25*(InstPeriod) + .75*Period[1]
    Period
    
//Get highest val in period
getHighest(src, len)=>
    H = src[len]
    for i=0 to len
        if src[i]>H
            H := src[i]
    H
    
//Get lowest val in period
getLowest(src, len)=>
    L = src[len]
    for i=0 to len
        if src[i]<L
            L := src[i]
    L

if transform == "Hilbert"
    Length := round(getHT(Price)/2)
if transform == "Inphase-Quadrature"
    Length := round(getIQ(Price,min,50)/2)
if Length<min
    Length := min
    

Num = 0.0
Denom = 0.0
CG = 0.0
MaxCG = 0.0
MinCG = 0.0
Value1 = 0.0
Value2 = 0.0
Value3 = 0.0
for i = 0 to Length - 1
    Num := Num + (1 + i)*(Price[i])
    Denom := Denom + (Price[i])
if(Denom != 0)
    CG := -Num/Denom + (Length + 1) / 2
MaxCG := getHighest(CG, Length)
MinCG := getLowest(CG, Length)
if(MaxCG != MinCG)
    Value1 := (CG - MinCG) / (MaxCG - MinCG)
Value2 := (4*Value1 + 3*Value1[1] + 2*Value1[2] + Value1[3]) / 10
Value3 := .5*log((1+1.98*(Value2-.5))/(1-1.98*(Value2-.5)))

plot(Value3, "CG",orange, linewidth=2)
plot(Value3[1], "Trigger",green, linewidth=2)
hline(0,color=color(black,60))
hline(2,linestyle=hline.style_solid,color=color(black,70))
hline(-2,linestyle=hline.style_solid,color=color(black,70))

sell = crossover(Value3[1],Value3) and Value3 > sellTreshold
buy = crossunder(Value3[1],Value3) and Value3 < buyTreshold

strategy.entry("Long", strategy.long, when= buy and window())
strategy.exit("Exit", loss=fixedSL, trail_offset=trailTP, trail_points=fixedTP)
strategy.exit("Exit", when= sell)

strategy.entry("Short", strategy.short, when= sell and window())
strategy.exit("Exit", loss=fixedSL, trail_offset=trailTP, trail_points=fixedTP)
strategy.exit("Exit", when= buy)

更多内容