Estratégia de negociação de arbitragem de oscilador estocástico de quadro duplo

STOCH KDJ MA RSI VWMA SMA EMA WMA
Data de criação: 2025-06-18 13:47:35 última modificação: 2025-06-18 13:47:35
cópia: 0 Cliques: 318
2
focar em
319
Seguidores

Estratégia de negociação de arbitragem de oscilador estocástico de quadro duplo Estratégia de negociação de arbitragem de oscilador estocástico de quadro duplo

Visão geral

A estratégia de negociação de arbitragem de indicadores de oscilação aleatória de dois quadros é um sistema de negociação de alta frequência diária baseado em indicadores de oscilação aleatória (Stochastic Oscillator), cujo núcleo utiliza dois indicadores de oscilação aleatória de diferentes configurações de parâmetros para a geração e confirmação de sinais de negociação em um período de 15 segundos. A lógica principal é identificar pontos de entrada em potencial através da interseção da linha% K com a linha% D do indicador aleatório principal, enquanto o valor% D do indicador aleatório secundário é usado como um filtro de estado de mercado, combinando a média móvel e as condições de filtragem de tempo do mercado para construir um sistema de negociação com um mecanismo de confirmação em vários níveis.

Princípio da estratégia

A estratégia utiliza um sistema duplo de indicadores aleatórios de tremor, conhecidos como indicadores principais e indicadores de referência, respectivamente:

  1. Os principais parâmetros aleatórios de seqüência são:

    • Quadro de tempo: 15 segundos
    • K comprimento de linha: 12
    • Suavidade da linha K: 12
    • D comprimento de linha: 12
  2. Para se referir a configurações aleatórias do indicador de tremores:

    • Quadro de tempo: 15 segundos
    • K comprimento de linha: 12
    • A suavidade da linha K: 15
    • D comprimento de linha: 30

O design da lógica de entrada é refinado, e a eficácia do sinal é confirmada em vários níveis:

  • Requisitos de admissão:

    • O indicador principal %K atravessa a linha %D, e
    • Indicador de referência %D ≥ 50 ou < 20, ou
    • O indicador principal %K está próximo do indicador de referência %D (diferença dentro de 0,15)
    • Preço acima da média móvel (se o filtro MA estiver ativado)
    • O horário de negociação deve ocorrer durante o horário de mercado normal (9:30 AM - 4:00 PM ET)
  • Condições de entrada:

    • O indicador principal %K atravessa a linha %D, e
    • dentro do intervalo de tolerância do indicador de referência %D, ou satisfazendo condições de subtração específicas
    • Preços abaixo da média móvel
    • O horário de negociação deve ser o horário normal do mercado.

A lógica de saída baseia-se numa combinação de sinais de tempo e de tecnologia:

  • Tempo de saída:
    • A partir das 15h30 (horário de Brasília)
  • A saída técnica:
    • Posições múltiplas: quando o indicador principal %K atravessa o indicador de referência %D
    • Posição em branco: quando o indicador principal %K usa o indicador de referência%D e o indicador de referência%D>20

A estratégia também integra a identificação de formas:

  • Forma de ponto mais baixo: o valor de K% do ponto de desvio atual é maior do que o valor de K% do ponto de desvio anterior (forma de continuação da tendência)
  • Modo de alta mais baixa: o valor de K% do ponto de penetração atual é menor do que o valor de K% do ponto de penetração anterior (modo de continuação de baixa)

Vantagens estratégicas

  1. Mecanismos de confirmação múltipla: através de dois indicadores de vibração aleatórios de configurações diferentes, a confirmação mútua, reduzir o falso sinal produzido por um único indicador, aumentar a confiabilidade do sinal.

  2. Regras precisas de entrada e saídaA estratégia define condições de entrada e saída claras, elimina a subjetividade das decisões de negociação e permite uma negociação totalmente sistematizada.

  3. Identificação de formasA capacidade de identificar os padrões de “altos mais baixos” e “altos mais baixos” no mercado, para capturar oportunidades de continuação de tendências, é algo que muitas estratégias simples não conseguem fazer.

  4. Filtro de tempoA redução dos pontos de deslizamento e custos, evitando os períodos de alta volatilidade e baixa liquidez antes da abertura e do fechamento, limitando o tempo de negociação ao horário do mercado normal.

  5. Média móvel filtradaO filtro de média móvel opcional adiciona uma camada de confirmação de tendência para garantir que a direção da negociação esteja de acordo com a tendência geral.

  6. Diferenças de preço e parâmetros de capacidadeA estratégia introduziu vários parâmetros para controlar a amplitude de variação dos preços e a amplitude de variação do indicador, filtrando eficazmente os sinais de ruído gerados por pequenas flutuações.

  7. Conversão de lógica dinâmicaO sistema é capaz de ajustar as condições de conversão de multi-cabeça para a cabecera e de cabecera para multi-cabeça com base na dinâmica da situação do mercado, sendo mais adaptável.

  8. Sistema de alerta completoA estratégia integra uma ampla variedade de condições de alerta para monitorar e executar transações em tempo real.

Risco estratégico

  1. Risco de transações de alta frequência em um período de tempo curtoA estratégia de usar o prazo de 15 segundos pode gerar muitos sinais, resultando em transações frequentes, aumentando os custos de transação e podendo gerar uma grande quantidade de falsos sinais em situações de grande volatilidade no mercado.

  2. Falta de mecanismos de contençãoA falta de controle de risco é um dos principais pontos fracos da estratégia.

  3. Sensibilidade do parâmetroOs vários parâmetros precisos usados na estratégia, como o limiar de diferença de 0,15 e o limite de diferença de preço de 0,1% podem ser sensíveis a diferentes condições de mercado e precisam ser ajustados com frequência.

  4. O custo de oportunidade de uma limitação de tempoA negociação apenas durante o horário normal do mercado pode perder algumas oportunidades importantes antes e depois do fechamento, especialmente após a reação do mercado a um grande comunicado de imprensa.

  5. Dependência de liquidezA estratégia de alta frequência pode enfrentar problemas de deslizamento em mercados de baixa liquidez, onde o preço de execução real pode diferir significativamente do preço no momento da geração do sinal.

  6. Indicadores técnicos atrasadosO indicador de oscilação aleatória tem um certo atraso em si, especialmente em mercados de rápida reversão, e pode não ser capaz de capturar os pontos de inflexão em tempo hábil.

  7. Risco de sobreajusteO excesso de ajuste de parâmetros de estratégia pode levar a um excesso de ajuste de dados históricos e a um fraco desempenho no futuro ambiente de mercado.

Direção de otimização da estratégia

  1. Aumentar o mecanismo de suspensão de perdasO ponto de otimização mais importante é a implementação de um sistema de stop loss inteligente, que pode considerar uma estratégia de stop loss baseada no ATR, ou usar o nível de tecnologia como ponto de stop loss para limitar o máximo de perdas em uma única transação.

  2. Introdução à gestão de posições: Adaptação dinâmica da escala de negociação com base na volatilidade do mercado e na tolerância de risco da conta, usando diferentes posições em diferentes intensidades de sinal para otimizar a utilização dos fundos e a taxa de retorno do risco.

  3. Adição de confirmação de volumeA integração de indicadores de volume de transação no sistema exige que os sinais de entrada importantes tenham suporte suficiente para o volume de transação, o que pode filtrar os sinais não confiáveis em ambientes de baixo volume de transação.

  4. Integração de múltiplos indicadoresConsidere a combinação de outros indicadores de dinâmica e tendência, como RSI, MACD ou Brinks, para construir uma visão mais abrangente do mercado e melhorar a robustez do sistema.

  5. Otimização de prazosTestar diferentes prazos de tempo básicos, como 1 minuto ou 5 minutos, que podem reduzir o ruído e, ao mesmo tempo, manter oportunidades de negociação suficientes para encontrar o melhor equilíbrio entre a qualidade e a quantidade de sinais.

  6. Aumentar o rastreamento estatísticoA implementação de indicadores de desempenho de retorno mais abrangentes, como a máxima retirada, a taxa de Sharpe, a taxa de vitória, a taxa de ganhos e perdas, etc., para avaliar o desempenho da estratégia de forma mais científica.

  7. Parâmetros de adaptaçãoTransformar parâmetros fixos em parâmetros de adaptação baseados em variações dinâmicas de mercado, permitindo que a estratégia se adapte a diferentes condições de mercado.

  8. Aumentar a filtragem de mercadoAdicionar o VIX (indice de volatilidade) ou indicadores similares como condições de filtragem do mercado, ajustar os parâmetros de estratégia ou suspender a negociação em um ambiente de alta volatilidade.

Resumir

A estratégia de negociação de arbitragem de indicadores de oscilação aleatória de quadros de dois tempos é um sistema de negociação de alta frequência de curto prazo bem projetado, que aumenta a confiabilidade dos sinais de negociação por meio de mecanismos de confirmação em várias camadas, como indicadores de oscilação aleatória dupla, filtragem de médias móveis e filtragem de tempo. A estratégia identifica pontos de inflexão e tendências de continuação de overbought e overbought de curto prazo em períodos de mercado regulares e é adequada para mercados com liquidez suficiente e volatilidade moderada.

Apesar da estrutura de design da estratégia ser perfeita, ainda existem deficiências nos mecanismos de gerenciamento de riscos-chave, como os riscos inerentes à negociação de alta frequência e a falta de stop loss. Para melhorar a robustez e a rentabilidade a longo prazo da estratégia, recomenda-se a adição de medidas de otimização, como o stop loss, o sistema de gerenciamento de posição, a confirmação de volume de transação e a integração de vários indicadores. Além disso, a transformação dos parâmetros fixos em parâmetros de adaptação e o aumento do rastreamento estatístico de retorno completo ajudarão a manter o desempenho estável da estratégia em diferentes ambientes de mercado.

Com a compreensão profunda e a otimização contínua da estratégia por parte dos traders, o sistema de negociação tem o potencial de se tornar uma parte eficaz do kit de ferramentas de negociação intradiária, especialmente adequado para o uso de traders com uma compreensão profunda dos indicadores técnicos e capazes de monitorar o mercado em tempo hábil.

Código-fonte da estratégia
/*backtest
start: 2025-01-01 00:00:00
end: 2025-06-17 00:00:00
period: 4h
basePeriod: 4h
exchanges: [{"eid":"Binance","currency":"ETH_USDT"}]
*/

//@version=6
strategy("Dual TF Stochastic Strategy", overlay=false)

// Input parameters with updated defaults
primaryLen = input.int(12, "Primary Stoch K Length", minval=1)  // Changed from 14 to 12
primarySmooth = input.int(12, "Primary Stoch K Smoothing", minval=1)  // Changed from 3 to 12
primaryDLen = input.int(12, "Primary Stoch D Length", minval=1)  // Changed from 3 to 12
primaryRes = input.timeframe("15S", "Primary Timeframe")  // Changed from "" to "15S"

refLen = input.int(12, "Reference Stoch K Length", minval=1)  // Changed from 14 to 12
refSmooth = input.int(15, "Reference Stoch K Smoothing", minval=1)  // Changed from 3 to 15
refDLen = input.int(30, "Reference Stoch D Length", minval=1)  // Changed from 3 to 30
refRes = input.timeframe("15S", "Reference Timeframe")  // Changed from "D" to "15S"

tolerance = input.float(0.1, "Ref D Tolerance %", minval=0.1, maxval=10.0, step=0.1)  // Changed from 1.0 to 0.1
maxPriceDiff = input.float(0.1, "Maximum Price % Difference", minval=0.1, maxval=5.0, step=0.1)  // Changed from 1.0 to 0.1
closeKThreshold = input.float(0.7, "Close %K Tolerance %", minval=0.1, maxval=10.0, step=0.1)  // Changed from 5.0 to 0.7
minPriceDiffShort = input.float(0.1, "Min Price % Diff for Close %K Short", minval=0.1, maxval=5.0, step=0.1)  // Changed from 0.5 to 0.1
showLabels = input.bool(true, "Show Crossover/Crossunder Labels")

// Time Filters (America/New_York timezone, UTC-4)
is_premarket = hour(time, "America/New_York") < 9
is_postmarket = hour(time, "America/New_York") >= 16
is_regular_hours = hour(time, "America/New_York") >= 9 and hour(time, "America/New_York") < 16
is_exit_time = hour(time, "America/New_York") >= 15 and minute(time, "America/New_York") >= 30  // 3:30 PM ET

// Moving Average Settings
useMAFilter = input.bool(true, "Use Moving Average Filter")
maLength = input.int(200, "Moving Average Length", minval=1)
maType = input.string("SMA", "Moving Average Type", options=["SMA", "EMA", "WMA", "VWMA"])
maTimeframe = input.timeframe("", "Moving Average Timeframe")

// Stochastic Calculations
primaryHighest = ta.highest(high, primaryLen)
primaryLowest = ta.lowest(low, primaryLen)
primaryK_raw = 100 * (close - primaryLowest) / (primaryHighest - primaryLowest)
primaryK = ta.sma(primaryK_raw, primarySmooth)
primaryD = ta.sma(primaryK, primaryDLen)
[primaryK_tf, primaryD_tf] = request.security(syminfo.tickerid, primaryRes, [primaryK, primaryD])

refHighest = ta.highest(high, refLen)
refLowest = ta.lowest(low, refLen)
refK_raw = 100 * (close - refLowest) / (refHighest - refLowest)
refK = ta.sma(refK_raw, refSmooth)
refD = ta.sma(refK, refDLen)
[refK_tf, refD_tf] = request.security(syminfo.tickerid, refRes, [refK, refD])

// Calculate Moving Average
var float ma = na
if useMAFilter
    if maType == "SMA"
        ma := request.security(syminfo.tickerid, maTimeframe, ta.sma(close, maLength))
    else if maType == "EMA"
        ma := request.security(syminfo.tickerid, maTimeframe, ta.ema(close, maLength))
    else if maType == "WMA"
        ma := request.security(syminfo.tickerid, maTimeframe, ta.wma(close, maLength))
    else if maType == "VWMA"
        ma := request.security(syminfo.tickerid, maTimeframe, ta.vwma(close, maLength))

// Price relative to MA
priceAboveMA = not useMAFilter or close > ma
priceBelowMA = not useMAFilter or close < ma

// Crossover Detection and Tracking
crossOver = ta.crossover(primaryK_tf, primaryD_tf)
crossUnder = ta.crossunder(primaryK_tf, primaryD_tf)

// Separate tracking for crossover and crossunder %K and price
var float lastCrossOverK = na
var float lastCrossOverPrice = na
var float currentCrossOverK = na
var float currentCrossOverPrice = na

var float lastCrossUnderK = na
var float lastCrossUnderPrice = na
var float currentCrossUnderK = na
var float currentCrossUnderPrice = na

// Update crossover tracking variables
if crossOver
    lastCrossOverK := nz(currentCrossOverK, primaryK_tf[1])
    lastCrossOverPrice := nz(currentCrossOverPrice, close[1])
    currentCrossOverK := primaryK_tf
    currentCrossOverPrice := close

// Update crossunder tracking variables
if crossUnder
    lastCrossUnderK := nz(currentCrossUnderK, primaryK_tf[1])
    lastCrossUnderPrice := nz(currentCrossUnderPrice, close[1])
    currentCrossUnderK := primaryK_tf
    currentCrossUnderPrice := close

// Calculate differences separately
crossOverPriceDiffPercent = math.abs((currentCrossOverPrice - lastCrossOverPrice) / lastCrossOverPrice * 100)
crossOverKDiffPercent = math.abs((currentCrossOverK - lastCrossOverK) / lastCrossOverK * 100)
crossUnderPriceDiffPercent = math.abs((currentCrossUnderPrice - lastCrossUnderPrice) / lastCrossUnderPrice * 100)
crossUnderKDiffPercent = math.abs((currentCrossUnderK - lastCrossUnderK) / lastCrossUnderK * 100)

isKCloseCrossUnder = crossUnderKDiffPercent <= closeKThreshold and not na(lastCrossUnderK)

// New condition for long entry based on %K and refD_tf difference
kAndRefDDiffClose = crossOver and math.abs(currentCrossOverK - refD_tf) <= 0.15

// Labels for crossover and crossunder (optional)
if showLabels
    if crossOver
        diffKandRefD = math.abs(currentCrossOverK - refD_tf)
        label.new(bar_index, 50, "CrossOver\nDiff K-RefD: " + str.tostring(diffKandRefD, "#.###"), color=color.green, textcolor=color.black, style=label.style_label_up)
    if crossUnder
        diffKandRefD = math.abs(currentCrossUnderK - refD_tf)
        label.new(bar_index, 50, "CrossUnder\nDiff K-RefD: " + str.tostring(diffKandRefD, "#.###"), color=color.red, textcolor=color.black, style=label.style_label_down)

// Entry Conditions
longKCondition = crossOver and (na(lastCrossOverK) or currentCrossOverK > lastCrossOverK)
shortKCondition = crossUnder and (crossUnderPriceDiffPercent <= maxPriceDiff)
closeKShortCondition = crossUnder and isKCloseCrossUnder and (crossUnderPriceDiffPercent > minPriceDiffShort)
crossUnderBetween50and45 = crossUnder and currentCrossUnderK <= 50 and currentCrossUnderK > 45

// Long to Short if crossunder %K > 80 OR < 60
longToShortCondition = crossUnder and (currentCrossUnderK > 80 or currentCrossUnderK < 60) and strategy.position_size > 0 and is_regular_hours

upperLimit = refD_tf * (1 + tolerance/100)
lowerLimit = refD_tf * (1 - tolerance/100)
withinToleranceLong = primaryK_tf >= lowerLimit and primaryK_tf <= upperLimit
withinToleranceShort = primaryK_tf >= lowerLimit and primaryK_tf <= upperLimit

// Final Entry Conditions with MA filter
longCondition = ((longKCondition and (refD_tf >= 50 or refD_tf < 20)) or kAndRefDDiffClose) and is_regular_hours and not is_exit_time and priceAboveMA
shortCondition = (shortKCondition or (crossUnder and withinToleranceShort and (crossUnderPriceDiffPercent <= maxPriceDiff)) or closeKShortCondition or longToShortCondition or crossUnderBetween50and45) and is_regular_hours and not is_exit_time and priceBelowMA

// Short-to-Long Transition Condition with MA filter
shortToLongCondition = crossOver and currentCrossOverK < 25 and strategy.position_size < 0 and is_regular_hours and not is_exit_time and priceAboveMA

// Tracking for %K crossing under refD_tf
var float lastPrimaryKCrossUnderRefD = na
var float currentPrimaryKCrossUnderRefD = na
var bool isPrimaryKCrossUnderRefD = false

// Check if primary %K crosses under reference %D
isPrimaryKCrossUnderRefD := ta.crossunder(primaryK_tf, refD_tf)

// Update tracking for %K crossing under refD
if isPrimaryKCrossUnderRefD
    lastPrimaryKCrossUnderRefD := currentPrimaryKCrossUnderRefD
    currentPrimaryKCrossUnderRefD := primaryK_tf

// Exit Conditions
if is_exit_time
    strategy.close("Long")
    strategy.close("Short")
else if isPrimaryKCrossUnderRefD and not na(lastPrimaryKCrossUnderRefD) and currentPrimaryKCrossUnderRefD < lastPrimaryKCrossUnderRefD
    strategy.close("Long")
else if (ta.crossunder(primaryK_tf, primaryD_tf) and primaryK_tf < refD_tf and refD_tf < 60)
    strategy.close("Long")

if (ta.crossover(primaryK_tf, primaryD_tf) and primaryK_tf > refD_tf and refD_tf > 20) and not is_exit_time
    strategy.close("Short")

// Track if crossunder happens above 85
var bool crossUnderAbove85 = false

// Detect crossunder above 85
if crossUnder and currentCrossUnderK > 85
    crossUnderAbove85 := true

// Reset condition if %K crosses over %D
if ta.crossover(primaryK_tf, primaryD_tf)
    crossUnderAbove85 := false

// Track previous crossover/crossunder values for Higher Low/Lower High detection
var float prevCrossOverK = na
var float prevCrossUnderK = na

// Update previous values on new crossovers/crossunders
if crossOver
    prevCrossOverK := currentCrossOverK
if crossUnder
    prevCrossUnderK := currentCrossUnderK

// Higher Low and Lower High conditions
higherLowCondition = crossOver and not na(prevCrossOverK) and currentCrossOverK > prevCrossOverK
lowerHighCondition = crossUnder and not na(prevCrossUnderK) and currentCrossUnderK < prevCrossUnderK

// Strategy Entries and Transitions
if longCondition
    strategy.entry("Long", strategy.long)

if shortCondition
    if strategy.position_size > 0  // If in a long position, close it first
        strategy.close("Long")
    strategy.entry("Short", strategy.short)

if shortToLongCondition
    strategy.close("Short")
    if ((longKCondition and (refD_tf >= 50 or refD_tf < 20)) or kAndRefDDiffClose)  // Check full longCondition minus time (already checked)
        strategy.entry("Long", strategy.long)

// Add label for Short to Long Transition
if shortToLongCondition
    label.new(bar_index, na, "T", color=color.green, textcolor=color.white, style=label.style_label_up)

// Add label for Long to Short Transition
if longToShortCondition
    label.new(bar_index, na, "T", color=color.red, textcolor=color.white, style=label.style_label_down)

// Plotting
plot(primaryK_tf, "Primary %K", color=color.white, linewidth=1)
plot(primaryD_tf, "Primary %D", color=color.orange, linewidth=1)
plot(refK_tf, "Reference %K", color=color.navy, linewidth=1)
plot(refD_tf, "Reference %D", color=color.rgb(33, 233, 243), linewidth=2)

// Plot current and last %K only for crossUnder when isKCloseCrossUnder is true and currentCrossUnderK < lastCrossUnderK
plot(crossUnder and isKCloseCrossUnder and currentCrossUnderK < lastCrossUnderK ? currentCrossUnderK : na, "Current CrossUnder %K (Close)", color=color.green, style=plot.style_cross, linewidth=2)
plot(crossUnder and isKCloseCrossUnder and currentCrossUnderK < lastCrossUnderK ? lastCrossUnderK : na, "Last CrossUnder %K (Close)", color=color.red, style=plot.style_cross, linewidth=2)

h0 = hline(85, "Upper Band", color=color.rgb(242, 187, 21))
hline(50, "Middle Band", color=#eaff04)
h1 = hline(20, "Lower Band", color=color.rgb(242, 187, 21))
h2 = hline(40, "Lower Band", color=#787B86)
h3 = hline(60, "Lower Band", color=#787B86)
h = hline(0, "Lower Band", color=#787B86)
h5 = hline(100, "Lower Band", color=#787B86)
fill(h0, h1, color=color.rgb(33, 150, 243, 90), title="Background")
fill(h, h1, color=#1be2781d, title="Background")
fill(h0, h5, color=#e21b742d, title="Background")

// Plot the MA if enabled
plot(useMAFilter ? ma : na, "Moving Average", color=color.yellow, linewidth=2)

// Add plot for visualization (optional)
plot(isPrimaryKCrossUnderRefD ? primaryK_tf : na, "Primary %K CrossUnder RefD", color=color.purple, style=plot.style_cross, linewidth=2)
plot(isPrimaryKCrossUnderRefD and not na(lastPrimaryKCrossUnderRefD) ? lastPrimaryKCrossUnderRefD : na, "Last Primary %K CrossUnder RefD", color=color.fuchsia, style=plot.style_cross, linewidth=2)

// Add new alert conditions
alertcondition(higherLowCondition, title="Stoch Higher Low", message="Stoch Higher Low Pattern Detected")
alertcondition(lowerHighCondition, title="Stoch Lower High", message="Stoch Lower High Pattern Detected")

// Plot markers for Higher Low and Lower High patterns
plot(higherLowCondition ? currentCrossOverK : na, "Higher Low", color=color.green, style=plot.style_cross, linewidth=2)
plot(lowerHighCondition ? currentCrossUnderK : na, "Lower High", color=color.red, style=plot.style_cross, linewidth=2)

// Alert conditions
alertcondition(crossOver, title="Stochastic %K Crossed Over %D", message="Stochastic %K crossed over %D")
alertcondition(crossUnder, title="Stochastic %K Crossed Under %D", message="Stochastic %K crossed under %D")
alertcondition(crossOver and primaryK_tf > 50, title="Stochastic %K Crossed Over %D Above 50", message="Stochastic %K crossed over %D above 50")
alertcondition(crossOver and primaryK_tf > refD_tf, title="Stochastic %K Crossed Over %D Above Reference %D", message="Stochastic %K crossed over %D above Reference %D")
alertcondition(longCondition, title="Long Entry Signal", message="Long entry signal triggered")
alertcondition(shortCondition, title="Short Entry Signal", message="Short entry signal triggered")
alertcondition(shortToLongCondition, title="Short to Long Transition", message="Short to Long transition triggered")
alertcondition(longToShortCondition, title="Long to Short Transition", message="Long to Short transition triggered")
alertcondition(isPrimaryKCrossUnderRefD, title="Primary %K Crossed Under Reference %D", message="Primary %K crossed under Reference %D")
alertcondition(crossOver and primaryK_tf > refD_tf, title="Bullish Crossover Above Ref %D", message="Bull: Dual Stoch")
alertcondition(crossUnder and primaryK_tf < refD_tf, title="Bearish Crossunder Below Ref %D", message="Bear: Dual Stoch")