혼합 거래 전략


생성 날짜: 2024-01-22 11:59:58 마지막으로 수정됨: 2024-01-22 11:59:58
복사: 2 클릭수: 537
avatar of ChaoZhang ChaoZhang
1
집중하다
1617
수행원

혼합 거래 전략

개요

S&P500 혼합 계절적 거래 전략은 계절적 법칙을 이용한 주식 거래의 양적 전략이다. 이 전략은 강화형 구매 보유 시스템, 기술 지표 조건 및 자본 흐름 지표를 결합하여 1 년 동안 더 나은 거래 달과 더 나쁜 거래 달 사이에 순환을 가능하게 한다.

전략 원칙

전략의 거래 신호와 규칙은 주로 다음과 같습니다.

  1. 매년 10월 첫째 거래일 개시시점에 추가 입점한다.
  2. VIX가 60% 이상 또는 15일 ATR이 90% 이상일 때, 계절적 거래는 일시 중단하고 시장의 변동이 진정될 때까지 입장을 기다립니다.
  3. 매년 8월 첫째 거래일 개시시 평점.
  4. VIX가 120%를 넘거나 VFI가 20을 넘어서 10일 평균이 하향하면 평점 신호를 낸다.
  5. 코스피 거래에 가입할 수 있습니다.

이 전략은 주식 시장이 1 년 동안의 불균형한 성과를 내는 규칙, 역사적으로 통계적으로 더 좋은 성과를 낸 10-4 월에 더 많이 하고, 역사적으로 더 나쁜 성과를 낸 5-9 월에 정지 또는 하위권을 하고, 역전 거래한다. 한편, 전략에는 시장의 큰 변동이 있을 때 거래를 일시 중단하는 기술 지표 조건이 추가되어 위험을 피하는 데 도움이 된다.

우위 분석

S&P500 혼합 계절적 거래 전략은 다음과 같은 장점이 있다:

  1. 성숙하고 안정적인 계절적 법칙을 이용한다. 이 전략은 S&P500 지수가 1년 동안 눈에 띄게 다른 달의 성과를 보여준다는 사실에 기초한다.
  2. 다양한 필터링 조건과 함께. 전략은 VIX, ATR, VFI와 같은 여러 조건을 추가하여 Noise를 효과적으로 필터링하고 더 신뢰할 수있는 거래 신호를 발송할 수 있습니다.
  3. 조정 가능한 거래 규칙. 전략은 선택적으로 추가하거나 제거 할 수 있으며, 거래 달은 필요에 따라 조정 할 수 있으며, 테스트 및 최적화가 쉽습니다.
  4. 내장된 위험 회피 메커니즘. VIX와 ATR의 변동성 검출은 시장의 급격한 변동의 영향을 효과적으로 회피할 수 있다.
  5. 자본 흐름 지표 보조 판단. VFI는 시장 참가자의 자본 흐름을 반영하여 전략적 의사 결정에 대한 추가 근거를 제공합니다.

위험 분석

S&P500의 혼합된 계절적 거래 전략에도 몇 가지 잠재적인 위험이 있습니다.

  1. 역사적 법칙이 유효하지 않을 위험. 주식 시장의 운행에는 강한 불확실성이 있으며, 역사적 법칙이 항상 유효할 필요는 없다.
  2. 기술 지표가 잘못된 신호를 보내는 위험. VIX, ATR, VFI 등 지표도 잘못된 판단이 발생할 수 있다.
  3. 매개 변수 최적화 불완전한 위험. 전략 매개 변수는 추가 테스트 및 최적화 할 수 있으며, 기존 매개 변수는 최적화되지 않을 수 있습니다.
  4. 공짜 거래에 대한 추가 위험. 선택적인 공짜 거래는 무제한의 손실을 초래할 수 있습니다.

위험 관리, 지표 조합, 변수 조정, 기계 학습을 도입하는 등의 방법으로 전략을 더욱 강화하여 위와 같은 위험을 해결할 수 있습니다.

최적화 방향

S&P500 혼합 계절적 거래 전략은 다음과 같은 측면에서 더욱 최적화 될 수 있습니다.

  1. 테스트 더 긴 역사 데이터 훈련. 더 많은 역사 데이터를 사용하여 재 테스트 및 최적화 전략 매개 변수를 사용할 수 있습니다.
  2. 손해 제도를 추가한다. 부동 손해 또는 시간 손해를 설정할 수 있으며, 단독 손실을 효과적으로 제어한다.
  3. 최적화 기술 지표 파라미터. VIX, ATR 및 VFI의 파라미터를 조정하여 최적의 파라미터 조합을 찾습니다.
  4. 기계학습 모델을 도입한다. 신경망이나 의사결정 나무를 사용하여 변수를 스스로 적응하는 최적화한다.
  5. 전략 포트폴리오: 다른 전략과 결합하여 무관성을 사용하여 시장의 체계적 위험을 줄이는 전략을 테스트 할 수 있습니다.

요약하다

S&P500 혼합 계절 거래 전략은 성숙한 계절 규칙, 기술 지표 조건 및 자금 흐름 지표를 사용합니다. 이 전략은 주식 시장이 가장 좋지 않은 달을 피하고 일 년 중 가장 좋은 거래 달에配置되며, 효과적인 시장 변동 필터링 메커니즘을 내장하여 안정적인 초과 수익을 창출합니다. 또한, 전략은 테스트, 최적화 및 조정하기 쉽고, 또한 수량 거래자에게 참조 및 재개발 가능한 프레임 워크를 제공합니다. 더 많은 데이터, 손해 방지, 변수 조정 및 조합 방법 등을 도입함으로써 전략의 효과를 더욱 강화할 수 있습니다.

전략 소스 코드
/*backtest
start: 2023-12-01 00:00:00
end: 2023-12-31 23:59:59
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//  TASC Issue: April 2022 - Vol. 40, Issue 4
//     Article: Sell In May? Stock Market Seasonality                    
//  Article By: Markos Katsanos
//    Language: TradingView's Pine Script v5
// Provided By: PineCoders, for tradingview.com

//@version=5
strategy(title             = "TASC 2022.04 S&P500 Hybrid Seasonal System", 
         shorttitle        = "HSS v2.0",
         overlay           = true, 
         default_qty_type  = strategy.percent_of_equity, 
         default_qty_value = 10, 
         initial_capital   = 100000,
         currency          = currency.USD,
         commission_type   = strategy.commission.percent,
         commission_value  = 0.01
         )

// Helper Functions:

// @function Returns the ratio to max/min of a sample period
// @param src float, data source.
// @param length int, period of the sample.
// @returns [float, float] tuple.
volatility (float src, int length) =>
    [(src / ta.highest(src, length)[1] - 1.0) * 100.0,
     (src / ta.lowest (src, length)[1] - 1.0) * 100.0]

// @function Volume Flow Indicator.
// @param Period int, period of the data sample.
// @param VCoef float, Volume Volatility Coefficient.
// @param Coef float, Cutoff Coefficient.
// @returns float.
// ref: https://mkatsanos.com/volume-flow-vfi-indicator/
vfi (int Period = 130, float VCoef = 2.5, float Coef = 0.2) =>
    lastHLC3 = nz(hlc3[1], hlc3)
	MF     = hlc3  - lastHLC3
    Vinter = ta.stdev(math.log(hlc3) - math.log(lastHLC3), 30)
    Vave   = ta.sma(volume, Period)[1]
    Cutoff = Coef * close * Vinter
    VC     = math.min(volume, Vave * VCoef)
    VCP    = MF >  Cutoff ?  VC :
		     MF < -Cutoff ? -VC : 0.0
    VFI1 = nz(math.sum(VCP, Period) / Vave)
    VFI = ta.ema(VFI1, 3)


// inputs:
// optional strategy obserservation window parameters:
string ig_ow      = 'Observation Window:'
bool i_Sdate      = input(  title   = 'Start date:', 
                                 defval  = timestamp('2021-01-01'), 
                                 inline  = 'Sdate', 
                                 group   = ig_ow
                                 ) < time //
bool i_useSdate   = input.bool(  title   = '', 
                                 defval  = false, 
                                 group   = ig_ow, 
                                 inline  = 'Sdate', 
                                 tooltip = 'Optional start date to clamp strategy observation window.'
                                 ) //
bool i_Edate      = input(  title   = 'End date:', 
                                 defval  = timestamp('2022-01-01'), 
                                 inline  = 'Edate', 
                                 group   = ig_ow
                                 ) > time //
bool i_useEdate   = input.bool(  title   = '', 
                                 defval  = false, 
                                 group   = ig_ow, 
                                 inline  = 'Edate', 
                                 tooltip = 'Optional end date to clamp strategy observation window.'
                                 ) //
//
string ig_ro      = 'Lookback Options:'
int  i_lback      = input.int(   title   = 'Lookback Shift:', 
                                 defval  = 0, minval = 0,
                                 group   = ig_ro,
                                 tooltip = 'Optional, inspect previous signal values.'
                                 ) //
//
string ig_so      = 'Signal Options:'
bool i_onlyL      = input.bool(      title   = 'Long Only:', 
                                     defval  = true,
                                     group   = ig_so, 
                                     tooltip = 'If switched off, short entries are initiated by sell signals.'
                                     ) //
int  i_sMonth     = input.int(       title   = 'Sell Month:', 
                                     defval  = 8, minval = 1, maxval = 12, step = 1,
                                     group   = ig_so, 
                                     tooltip = 'The worst performing month, originally clamped between months 5 and 8.'
                                     ) //
int  i_maxVI      = input.int(       title   = 'Max VIX up:', 
                                     defval  = 60, minval = 50, maxval = 60, step = 5,
                                     group   = ig_so, 
                                     tooltip = 'Volatility maximum threshold.'
                                     ) //
int  i_critVFI    = input.int(       title   = 'Critical VFI Sell:', 
                                     defval  = -20, minval = -20, maxval = -15, step = 5, 
                                     group   = ig_so, 
                                     tooltip = 'Critical money float (VFI) threshold for sell signal.'
                                     ) //
float i_K         = input.float(     title   = 'ATR/VIX Ratio:', 
                                     defval  = 1.5, minval = 1.3, maxval = 1.7, step = 0.2, 
                                     group   = ig_so, 
                                     tooltip = 'ATR to VIX ratio for sell signal.'
                                     ) //
// 
string i_VIticker = input(    title   = 'Volatility Index:',
                                     defval  = 'VIX', 
                                     group   = ig_so,
                                     tooltip = 'Volatility Index Ticker.'
                                     ) //
string i_VItf     = input.timeframe( title   = '',
                                     defval  = 'D', 
                                     group   = ig_so,
                                     tooltip = 'Volatility Index Timeframe.'
                                     ) //
int i_VIiperiod   = input.int(       title   = 'Implied Volatility period:', 
                                     defval  = 25, 
                                     group   = ig_so
                                     ) //
int i_VIhperiod   = input.int(       title   = 'Historical Volatility period:', 
                                     defval  = 15, 
                                     group   = ig_so
                                     ) //
//
int i_VFIperiod   = input.int(   title   = 'VFI period:', 
                                 defval  = 130, 
                                 group   = ig_so, inline = 'VFI1'
                                 ) //
int i_VFIMperiod  = input.int(   title   = 'MA:', 
                                 defval  = 10, 
                                 group   = ig_so, inline = 'VFI1',
                                 tooltip = 'VFI and Moving Average sampling period.'
                                 ) //
float i_VFIcoef   = input.float( title   = 'VFI Coef Cuttoff:', 
                                 defval  = 0.2, 
                                 group   = ig_so, inline = 'VFI2'
                                 ) //
float i_VFIvcoef  = input.float( title   = 'Volat.:',
                                 defval  = 2.5, 
                                 group   = ig_so, inline = 'VFI2',
                                 tooltip = 'VFI Cutoff and Volatility coefficient.'
                                 ) //
int i_ATRperiod   = input.int(   title   = 'ATR length:',
                                 defval  = 15, 
                                 group = ig_so, inline = 'ATR',
                                 tooltip = 'ATR length.'
                                 ) // 
//
string ig_to = 'Table Options:'
bool i_showT =      input.bool(  title   = 'Show Table:',
                                 defval  = false, 
                                 group   = ig_to, 
                                 tooltip = 'Optional toggle.'
                                 ) //
string i_Tpos =     input.string(title   = 'Position:',
                                 defval  = position.middle_right, 
                                 options = [    position.top_left,     position.top_center,    position.top_right, 
                                             position.middle_left,  position.middle_center, position.middle_right,
                                             position.bottom_left,  position.bottom_center, position.bottom_right   ],
                                 group   = ig_to) //
int i_Ttransp  =      input.int( title   = 'Transparency:',
                                 defval  = 0, minval = 1, maxval = 99, 
                                 group   = ig_to
                                 ) //
//
color i_Tcframe =   input.color( title   = 'Table Colors:', 
                                 defval  = #000000, 
                                 group   = ig_to, inline = 'table color'
                                 ) //
color i_Tcrowe =    input.color( title   = '', 
                                 defval  = #d6dae3, 
                                 group   = ig_to, inline = 'table color'
                                 ) //
color i_Tcrowo =    input.color( title   = '', 
                                 defval  = #cccccc, 
                                 group   = ig_to, inline = 'table color', 
                                 tooltip = 'Table background colors, in order: frame, even row, odd row.'
                                 ) //
string i_Ttsize =   input.string(title   = 'Table Text:', 
                                 defval  = size.small,
                                 options = [size.auto, size.huge, size.large, size.normal, size.small, size.tiny],
                                 group   = ig_to, inline = 'table text'
                                 ) //
color i_Tcdeft =    input.color( title   = 'Text Colors:', 
                                 defval  = #000000, 
                                 group   = ig_to, inline = 'table text'
                                 ) //
color i_Tcsigt =    input.color( title   = '', 
                                 defval  = color.red, 
                                 group   = ig_to, inline = 'table text'
                                 ) //
color i_Tctitt =    input.color( title   = '', 
                                 defval  = color.navy, 
                                 group   = ig_to, inline = 'table text', 
                                 tooltip = 'Table text size and colors, in order: default, short signal, title.'
                                 ) //

// Comparison Index
float VIX      = request.security(i_VIticker, i_VItf, close)
[VIdn, VIup]   = volatility(VIX, i_VIiperiod)                   // Implied
[ATRdn, ATRup] = volatility(ta.atr(i_VIhperiod), i_VIiperiod)   // Historical

float VFI   = vfi(i_VFIperiod, i_VFIvcoef, i_VFIcoef)
float VFI10 = ta.sma(VFI, i_VFIMperiod)


//
bool VFIatCrit = VFI > i_critVFI
bool lowVolat  = (VIup < i_maxVI) or (ATRup < (i_K * i_maxVI))
bool VolatC    = VFIatCrit ? lowVolat : false
bool Long      = ((month >= 10) or (month < i_sMonth)) and VolatC[1]
bool Sseasonal = month == i_sMonth                                   // SEASONAL EXIT/SHORT
bool Svol      = VIup > (2.0 * i_maxVI)                              // VOLATILITY EXIT/SHORT
bool Scrit     = ta.cross(i_critVFI, VFI) and (VFI10 < VFI10[1])     // VFI EXIT/SHORT
bool Short     = Sseasonal or Svol[1] or Scrit[1]

bool withinObsWindow = true
//
if withinObsWindow and strategy.equity > 0
    _L = strategy.long
    _S = strategy.short
    strategy.entry('L'               , direction = _L,      when = Long      )
    if i_onlyL
        strategy.close('L', comment = 'EXIT SEASONAL'  ,    when = Sseasonal )
        strategy.close('L', comment = 'EXIT VOLATILITY',    when = Svol[1]   )
        strategy.close('L', comment = 'EXIT MF'        ,    when = Scrit[1]  )
    else
        strategy.entry('S Seasonal'  , direction = _S,      when = Sseasonal )
        strategy.entry('S Volatility', direction = _S,      when = Svol[1]   )
        strategy.entry('S MF Crit.'  , direction = _S,      when = Scrit[1]  )
else
    strategy.close_all()

string SIGNAL = switch
    (Long)                      => 'Long Seasonal'
    (Sseasonal and i_onlyL)     => 'Exit Seasonal'
    (Svol[1]   and i_onlyL)     => 'Exit Volatility'
    (Scrit[1]  and i_onlyL)     => 'Exit Money Flow'
    (Sseasonal and not i_onlyL) => 'Short Seasonal'
    (Svol[1]   and not i_onlyL) => 'Short Volatility'
    (Scrit[1]  and not i_onlyL) => 'Short Money Flow Bearish'
    =>                             'none'

string date = str.format(
  '{0,number,0000}-{1,number,00}-{2,number,00}', 
  year, month, dayofmonth
  )

var table dTable = table.new(position    = i_Tpos, 
                             columns     = 2, 
                             rows        = 17, 
                             frame_color = color.new(#000000, i_Ttransp), 
                             frame_width = 4
                             ) //


// @function Helper to populate the table rows.
tRow(tableId, idx, left, right, tcol=0) =>
    color _bg = color.new(idx % 2 ? i_Tcrowo : i_Tcrowe, i_Ttransp)
    color _tx = switch (tcol)
        (1)  => color.new(i_Tcsigt, i_Ttransp)
        (2)  => color.new(i_Tctitt, i_Ttransp)
        =>      color.new(i_Tcdeft, i_Ttransp)
    // table.cell(  table_id=tableId, 
    //              column=0, row=idx, 
    //              text=left, text_color=_tx, text_halign=text.align_right, text_size=i_Ttsize, 
    //              bgcolor=_bg) //
    // table.cell(  table_id=tableId, 
    //              column=1, row=idx, 
    //              text=str.tostring(right), text_color=_tx, text_halign=text.align_left, text_size=i_Ttsize, 
    //              bgcolor=_bg) //


if i_showT
    float _atr10 = ta.atr(10)[i_lback]
    string _nf = '0.00'
    string _aru = '🔼 ', string _ard = '🔽 '
    //      id | idx |                   left label  |                      right label  |               conditional color |
    tRow(dTable,   00, 'S&P500 Hybrid Seasonal '     , ''                                , 2                               )
    tRow(dTable,   01, 'Created By: Markos Katsanos' , ''                                , 2                               )
    tRow(dTable,   02, 'Date:'                       , date[i_lback]                                                       )
    tRow(dTable,   03, 'Signal:'                     , SIGNAL[i_lback]                                                     )
    tRow(dTable,   04, 'Price:'                      , open[i_lback]                                                       )
    tRow(dTable,   05, 'VIX:'                        , str.tostring(  VIX[i_lback], _nf)                                   )
    tRow(dTable,   06, 'VFI:'                        , str.tostring(  VFI[i_lback], _nf) , VFIatCrit ? 1 : 0               )
    tRow(dTable,   07, 'ATR:'                        , str.tostring(        _atr10, _nf)                                   )
    tRow(dTable,   08, 'VIup%:'                      , str.tostring( VIup[i_lback], _nf) , VIup > i_maxVI ? 1 : 0          )
    tRow(dTable,   09, 'ATRup%:'                     , str.tostring(ATRup[i_lback], _nf) , ATRup > i_K * i_maxVI ? 1 : 0   )
    tRow(dTable,   10, 'VIdn%:'                      , str.tostring( VIdn[i_lback], _nf)                                   )
    tRow(dTable,   11, 'ATRdn%:'                     , str.tostring(ATRdn[i_lback], _nf)                                   )
    tRow(dTable,   12, _aru + 'Long Seasonal:'       , Long[i_lback]                                                       )
    tmp = 12
    if not i_onlyL
        tmp := 13
        tRow(dTable, 13, _ard + 'Short:'             , Short[i_lback]                    , Short[i_lback] ? 1 : 0          )
    tRow(dTable,  tmp+1, _ard + 'Seasonal:'          , Sseasonal[i_lback]                , Sseasonal[i_lback] ? 1 : 0      )
    tRow(dTable,  tmp+2, _ard + 'Volatility:'        , Svol[1+i_lback]                   , Svol[1 + i_lback] ? 1 : 0       )
    tRow(dTable,  tmp+3, _ard + 'Money Flow:'        , Scrit[i_lback]                    , Scrit[i_lback] ? 1 : 0          )