양적 거래 플랫폼에 기반한 적응형 네트워크 거래 전략

저자:차오장, 날짜: 2024-02-21 10:55:21
태그:

img

전반적인 설명

이 전략은 양적 거래 플랫폼을 기반으로 한 적응적 그리드 거래 전략입니다. 자동 또는 수동 그리드 거래 범위를 설정하고 그레드 거래를 구현하기 위해 범위 내에서 동등한 간격으로 구매 및 판매 명령을합니다. 가격이 그리드의 상부 또는 하부 한계를 넘을 때 전략은 자동으로 그리드 범위를 조정합니다.

전략 원칙

  1. 네트워크에 대한 상위 및 하위 한계 가격을 설정합니다. 상위 및 하위 한계로 최고 및 최저 역사 가격의 특정 간격 내에서 가격을 자동으로 계산하거나 고정 상위 및 하위 한계 가격을 수동으로 설정합니다.

  2. 각 네트워크에 대한 가격 간격을 상위 및 하위 한계 가격 및 네트워크 수에 기초하여 계산합니다.

  3. 격자처럼 상위와 하위 한계 가격 사이에 동일한 간격으로 여러 구매 및 판매 지점을 배치하십시오.

  4. 시장 가격이 격자의 하단 한도를 넘으면 마지막 종료되지 않은 주문이 있는 격자 아래의 다음 격자에 구매 주문을 배치하고, 시장 가격이 격자의 상단 한도를 넘으면 마지막 종료되지 않은 주문이 있는 격자 위의 격자에 판매 주문을 배치합니다.

  5. 따라서, 그리드의 상부와 하부 경계 내에서 구매 및 판매 작업을 계속합니다. 가격 트렌드가 역전되면 이전 주문은 점차 수익을 얻거나 손실을 멈추게됩니다.

이점 분석

  1. 그리드 트레이딩은 범위와 오스실레이션 시장에서 이익을 얻을 수 있습니다.

  2. 네트워크 범위의 적응 조정은 수동 개입 없이 시장 변동에 따라 자동으로 조정할 수 있습니다.

  3. 자본 투자의 금액은 전력망에 위험을 배분하기 위해 미리 설정할 수 있습니다.

  4. 논리는 간단하고 이해하기 쉬우며, 매개 변수는 조정할 수 있습니다.

위험 분석

  1. 상위와 하위 한계를 넘어서면 손실이 발생할 수 있습니다.

    • 해결책: 합리적으로 스톱 로스 위치를 설정합니다.
  2. 시장의 흐름은 반복적인 손실로 이어질 수 있습니다.

    • 해결책: 트렌드를 파악하고 적시에 거래를 중단하십시오.
  3. 잘못된 매개 변수 설정

    • 솔루션: 그리드 양과 가격 간격 매개 변수를 조정합니다.

최적화 방향

  1. 기계 학습을 사용하여 가격 변동 범위와 동향을 예측하여 그리드 매개 변수를 동적으로 조정합니다.

  2. 트렌드 트레이딩을 트렌드 시장에서 트렌드 트레이딩으로 전환하여 그리드 트레이딩 손실을 피합니다.

  3. 자본 활용률, 수익률 등에 기반한 위험 관리 조치를 포함합니다.

  4. 자본 활용도를 높이기 위해 자산 종류에 따라 다양화하십시오.

결론

이 전략은 자동으로 조정 가능한 매개 변수를 가진 적응적 그리드 전략으로 변동 및 범위 제한 움직임이있는 주식, 암호화폐 및 외환 상품에 적합합니다. 조정된 매개 변수로 다른 시장 조건에 적응 할 수 있으며 실용적인 가치를 가지고 있습니다.


/*backtest
start: 2024-01-01 00:00:00
end: 2024-01-24 23:59:59
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=4
//hk4jerry

strategy("Grid Bot Backtesting", overlay=false, pyramiding=3000, close_entries_rule="ANY", default_qty_type=strategy.cash, initial_capital=100.0, currency="USD", commission_type=strategy.commission.percent, commission_value=0.025)
i_autoBounds    = input(group="Grid Bounds", title="Use Auto Bounds?", defval=true, type=input.bool)                             // calculate upper and lower bound of the grid automatically? This will theorhetically be less profitable, but will certainly require less attention
i_boundSrc      = input(group="Grid Bounds", title="(Auto) Bound Source", defval="Hi & Low", options=["Hi & Low", "Average"])     // should bounds of the auto grid be calculated from recent High & Low, or from a Simple Moving Average
i_boundLookback = input(group="Grid Bounds", title="(Auto) Bound Lookback", defval=250, type=input.integer, maxval=500, minval=0) // when calculating auto grid bounds, how far back should we look for a High & Low, or what should the length be of our sma
i_boundDev      = input(group="Grid Bounds", title="(Auto) Bound Deviation", defval=0.10, type=input.float, maxval=1, minval=-1)  // if sourcing auto bounds from High & Low, this percentage will (positive) widen or (negative) narrow the bound limits. If sourcing from Average, this is the deviation (up and down) from the sma, and CANNOT be negative.
i_upperBound    = input(group="Grid Bounds", title="(Manual) Upper Boundry(상단 가격)", defval=0.285, type=input.float)                      // for manual grid bounds only. The upperbound price of your grid
i_lowerBound    = input(group="Grid Bounds", title="(Manual) Lower Boundry(하단 가격)", defval=0.225, type=input.float)                      // for manual grid bounds only. The lowerbound price of your grid.
i_gridQty       = input(group="Grid Lines",  title="Grid Line Quantity(그리드 수)", defval=30, maxval=999, minval=1, type=input.integer)       // how many grid lines are in your grid
initial_balance = input(group="Trading option", title="Initial balance(투자금액)", defval=100, step=0.01)


start_time = input(group="Trading option",defval=timestamp('15 March 2023 06:00'), title='Start Time', type = input.time)
end_time = input(group="Trading option",defval=timestamp('31 Dec 2035 20:00'), title='End Time', type = input.time)
isAfterStartDate = true

tradingtime= (timenow - start_time)/(86400000*30)
yeartime=tradingtime/12


f_getGridBounds(_bs, _bl, _bd, _up) =>
    if _bs == "Hi & Low"
        _up ? highest(close, _bl) * (1 + _bd) : lowest(close, _bl)  * (1 - _bd)
    else
        avg = sma(close, _bl)
        _up ? avg * (1 + _bd) : avg * (1 - _bd)

f_buildGrid(_lb, _gw, _gq) =>
    gridArr = array.new_float(0)
    for i=0 to _gq-1
        array.push(gridArr, _lb+(_gw*i))
    gridArr

f_getNearGridLines(_gridArr, _price) =>
    arr = array.new_int(3)
    for i = 0 to array.size(_gridArr)-1
        if array.get(_gridArr, i) > _price
            array.set(arr, 0, i == array.size(_gridArr)-1 ? i : i+1)
            array.set(arr, 1, i == 0 ? i : i-1)
            break
    arr

var upperBound      = i_autoBounds ? f_getGridBounds(i_boundSrc, i_boundLookback, i_boundDev, true) : i_upperBound  // upperbound of our grid
var lowerBound      = i_autoBounds ? f_getGridBounds(i_boundSrc, i_boundLookback, i_boundDev, false) : i_lowerBound // lowerbound of our grid
var gridWidth       = (upperBound - lowerBound)/(i_gridQty-1)                                                       // space between lines in our grid
var gridLineArr     = f_buildGrid(lowerBound, gridWidth, i_gridQty)                                                 // an array of prices that correspond to our grid lines
var orderArr        = array.new_bool(i_gridQty, false)                                                              // a boolean array that indicates if there is an open order corresponding to each grid line

var closeLineArr    = f_getNearGridLines(gridLineArr, close)                                                        // for plotting purposes - an array of 2 indices that correspond to grid lines near price
var nearTopGridLine = array.get(closeLineArr, 0)                                                                    // for plotting purposes - the index (in our grid line array) of the closest grid line above current price
var nearBotGridLine = array.get(closeLineArr, 1)                                                                    // for plotting purposes - the index (in our grid line array) of the closest grid line below current price
if isAfterStartDate
    for i = 0 to (array.size(gridLineArr) - 1)
        if close < array.get(gridLineArr, i) and not array.get(orderArr, i) and i < (array.size(gridLineArr) - 1)
            buyId = i
            array.set(orderArr, buyId, true)
            strategy.entry(id=tostring(buyId), long=true, qty=(initial_balance/(i_gridQty-1))/close, comment="#"+tostring(buyId))
        if close > array.get(gridLineArr, i) and i != 0
            if array.get(orderArr, i-1)
                sellId = i-1
                array.set(orderArr, sellId, false)
                strategy.close(id=tostring(sellId), comment="#"+tostring(sellId))

    if i_autoBounds
        upperBound  := f_getGridBounds(i_boundSrc, i_boundLookback, i_boundDev, true)
        lowerBound  := f_getGridBounds(i_boundSrc, i_boundLookback, i_boundDev, false)
        gridWidth   := (upperBound - lowerBound)/(i_gridQty-1)
        gridLineArr := f_buildGrid(lowerBound, gridWidth, i_gridQty)

    closeLineArr    := f_getNearGridLines(gridLineArr, close)
    nearTopGridLine := array.get(closeLineArr, 0)
    nearBotGridLine := array.get(closeLineArr, 1)






var table table = table.new(position.top_right,6,8, frame_color = color.rgb(255, 255, 255),frame_width = 2,border_width = 2, border_color=color.rgb(255, 255, 255))
        


//제목
table.cell(table,0,0,"상단 라인 :", bgcolor=color.new(color.black,0),text_color =color.white)    
table.cell(table,0,1,"하단 라인 :",bgcolor=color.new(color.black,0),text_color =color.white)
table.cell(table,0,2,"그리드 수 :",bgcolor=color.new(color.black,0),text_color =color.white)
table.cell(table,0,3,"투자금액 :",text_color =color.white,bgcolor=color.new(color.black,0))
table.cell(table,0,4,"그리드당 투자금액 :",text_color =color.white,bgcolor=color.new(color.black,0))
//수치
table.cell(table,1,0, tostring(upperBound, '###.#####')+ "  USDT", bgcolor=color.new(#5a637e, 0),text_color =color.white)    
table.cell(table,1,1, tostring(lowerBound, '###.#####')+ "  USDT", bgcolor=color.new(#5a637e, 0),text_color =color.white)
table.cell(table,1,2, tostring(i_gridQty, '###'), bgcolor=color.new(#5a637e, 0),text_color =color.white)
table.cell(table,1,3, tostring(initial_balance,'###.##')+ "  USDT", bgcolor=color.new(#5a637e, 0),text_color =color.white)
table.cell(table,1,4, tostring(initial_balance/i_gridQty,'###.##')+ "  USDT", bgcolor=color.new(#5a637e, 0),text_color =color.white)

//제목
table.cell(table,2,0,"현재 포지션 :",text_color =color.white,bgcolor=color.new(color.black,0))
table.cell(table,2,1,"현재 포지션 평단가 :",text_color =color.white,bgcolor=color.new(color.black,0))
table.cell(table,2,2,"현재 포지션 수익 :",bgcolor=color.new(color.black,0),text_color =color.white)
table.cell(table,2,3,"현재 포지션 수익 % :",bgcolor=color.new(color.black,0),text_color =color.white)
table.cell(table,2,4,"현재 포지션 수수료 :",text_color =color.white,bgcolor=color.new(color.black,0))

//수치
table.cell(table,3,0, tostring(strategy.position_size) +   syminfo.basecurrency + "\n"  + tostring(strategy.position_size*strategy.position_avg_price/1, '###.##') + "USDT" ,text_color =color.white,bgcolor=color.new(#5a637e, 0))
table.cell(table,3,1, text=strategy.position_size>0 ? tostring(strategy.position_avg_price,'###.####')+ "  USDT" : "NOT TRADING",text_color =color.white,bgcolor=color.new(#5a637e, 0))
table.cell(table,3,2, tostring(strategy.openprofit, '###.##')+ "  USDT",text_color =color.white,bgcolor=strategy.openprofit > 0 ? color.teal : color.maroon)
table.cell(table,3,3, tostring(strategy.openprofit/initial_balance*100, '###.##')+ "%",text_color =color.white,bgcolor=strategy.openprofit > 0 ? color.teal : color.maroon)
table.cell(table,3,4, "-" + tostring(strategy.position_avg_price*strategy.position_size*0.025/100,'###.##')+ "  USDT",text_color =color.white,bgcolor=color.new(#5a637e, 0))

//제목
table.cell(table,4,0,"그리드 수익 :",text_color =color.white,bgcolor=color.new(color.black,0))
table.cell(table,4,1,"그리드 수익률 :",text_color =color.white,bgcolor=color.new(color.black,0))
table.cell(table,4,2,"총 수익 :", bgcolor=color.new(color.black,0),text_color =color.white)    
table.cell(table,4,3,"총 수익률 :",bgcolor=color.new(color.black,0),text_color =color.white)
table.cell(table,4,4,"현재 자산 :",bgcolor=color.new(color.black,0),text_color =color.white)


//수치
table.cell(table,5,0, tostring(strategy.netprofit, '###.#####')+ "USDT", text_color =color.white,bgcolor=strategy.netprofit > 0 ? color.teal : color.maroon)
table.cell(table,5,1, tostring((strategy.netprofit)/initial_balance*100/tradingtime, '####.##') + "%",text_color =color.white,bgcolor=strategy.netprofit > 0 ? color.teal : color.maroon)
table.cell(table,5,2, tostring(strategy.netprofit+strategy.openprofit, '###.##') + "  USDT",text_color =color.white,bgcolor=strategy.netprofit+strategy.openprofit > 0 ? color.teal : color.maroon)
table.cell(table,5,3, tostring((strategy.netprofit+strategy.openprofit)/initial_balance*100, '####.##') + "%",text_color =color.white,bgcolor=strategy.netprofit+strategy.openprofit > 0 ? color.teal : color.maroon)
table.cell(table,5,4, tostring(initial_balance+strategy.netprofit+strategy.openprofit, '###.##')+ "  USDT", text_color =color.white,bgcolor=color.new(#3d4d7c, 0))





// plot(strategy.initial_capital+ strategy.netprofit+strategy.openprofit, "총 수익 USDT",color=color.rgb(81, 137, 128))
// plot(initial_balance, "투자금액",color=color.rgb(81, 137, 128))

더 많은