
A estratégia de captura de tendências de reversão de volume é uma técnica de negociação quantitativa baseada em volumes e comportamentos de preços anormais, que visa identificar os momentos críticos em que o mercado pode sofrer uma reversão de direção. O núcleo da estratégia é encontrar linhas K com volumes de negociação significativamente acima da média e, ao confirmar a queda do volume de negociação, tomar decisões de negociação contrárias com base na direção da tendência anterior.
O princípio central da estratégia baseia-se na reversão de tendência após o volume de transações anormais no mercado. A lógica de operação específica é a seguinte:
Identificação de transações anormaisO sistema detecta se a linha K anterior tem volume de transação significativamente acima do nível médio. No período de negociação normal (RTH), o volume de transação precisa ser superior a 3 vezes o volume de transação médio recente (RTH) (ajustável); no período pós-closing ou especial (ETH), precisa ser superior a 5 vezes. O cálculo do volume médio de transação excluirá automaticamente o período de RTH marginal, 4-6 p.p. pós-closing e o período antes do fechamento de domingo.
Confirmação de que o volume de transações caiuO volume de transações na linha K atual deve ser menor do que o volume de transações na linha K anterior, indicando que as transações de grande volume terminaram.
Determinação da direção da tendência: Determine a direção da tendência comparando o preço de fechamento antes da linha K de volume anormal com a relação entre a SMA (média móvel simples).
Sinal de entrada de contracorrente:
Execução de entrada:
Gestão de RiscosDependendo das características de cada variedade, o sistema oferece duas opções de configuração de stop loss / stop stop:
Filtro de tempoA estratégia pode seletivamente filtrar os sinais de negociação dos primeiros e últimos 15 minutos do RTH e sempre filtrar os sinais do período de fechamento após o fechamento do RTH (entre 4 e 6 da tarde) e antes do fechamento do domingo.
Capturar pontos de inflexãoA estratégia concentra-se em capturar os pontos de inflexão do mercado que ocorrem com volumes anormais de negociação, que geralmente representam mudanças significativas no sentimento do mercado, oferecendo oportunidades de negociação com maior probabilidade de vitória.
Pontos de entrada precisosA utilização de um único limite de preço para entrar no ponto mais alto/mais baixo da linha K de volume de transação anormal, assegurando a negociação em níveis de preço tecnicamente importantes, aumentando a precisão de entrada.
A quantidade de adaptação identificadaA estratégia é ajustar dinamicamente os critérios de determinação do volume de transações anormais de acordo com os diferentes períodos de negociação (horário de negociação normal versus período pós-discote/horário especial), de modo a estar mais em sintonia com a realidade do mercado.
Gestão de Riscos Flexível: Disponibiliza opções de stop/stop baseadas em pontos fixos e ATR, com configurações personalizadas de acordo com as características e a volatilidade de diferentes variedades.
Filtro de tempo inteligenteO sistema de negociação de Forex (Forex) é um sistema de negociação de criptomoedas que permite identificar automaticamente e filtrar os momentos de baixa liquidez e instabilidade, evitando os falsos sinais que são fáceis de surgir perto da abertura e do fechamento do mercado.
Comentário visual claroA estratégia fornece indicações visuais intuitivas no gráfico, incluindo a linha K de volume anormal, a linha SMA de tendência e o equilíbrio de stop loss, facilitando a monitorização e análise dos comerciantes.
Execução automáticaO sistema executa automaticamente as ordens de limite e de stop loss, reduzindo a interferência humana e mantendo a disciplina de negociação.
Risco de Falso BreakoutO volume anormal de negociação pode levar o preço a ultrapassar níveis importantes por um curto período de tempo, mas depois pode retroceder rapidamente, causando um sinal errado. Para mitigar este risco, pode-se considerar o aumento de indicadores de confirmação, como a confirmação de RSI de sobrecompra/excesso de venda ou a exigência de duração da ruptura.
Efeitos de eventos impulsionados pela notíciaOs principais dados econômicos ou anúncios de empresas podem causar volume de transações anormais, mas essas reações tendem a durar mais tempo do que a reverter imediatamente. Recomenda-se suspender a estratégia ou aumentar os requisitos de filtragem antes e depois da publicação de dados econômicos importantes.
Risco de mudanças no cenário de mercado: Em mercados de forte tendência, a negociação de contrapartida pode enfrentar uma tendência de preços persistentemente desfavorável. Considere a adição de filtros de tendência de longo prazo para evitar a operação de contrapartida em ambientes de forte tendência.
Risco de que o limite de preço não tenha sido negociado: Se o preço não atingir o nível de preço limite definido na linha K seguinte, o sinal de negociação pode ser invalidado. Pode ser considerado o estabelecimento de um prazo máximo de validade ou, em determinadas condições, a transferência para a execução do preço de mercado.
Risco de baixa liquidezApesar de a estratégia ter incluído a função de filtragem de tempo, algumas variedades ainda podem ter problemas de falta de liquidez em determinados períodos de tempo. Recomenda-se que os limites de tempo de negociação sejam ajustados para as características das variedades de negociação.
Riscos de otimização de parâmetrosOtimização excessiva de parâmetros de estratégia pode levar a um desempenho ruim no futuro por sobreajuste de dados históricos. Os parâmetros devem ser mantidos dentro de limites razoáveis e a robustez da estratégia deve ser verificada por testes fora da amostra.
Confirmação de múltiplos períodos de tempoPor exemplo, pode-se verificar a direção da tendência do dia-a-dia e só entrar em jogo quando coincide com a tendência do dia-a-dia.
Avaliação da qualidade do volume de transaçõesAlém do tamanho da capacidade de volume, pode-se considerar a avaliação da qualidade do volume de transação, como o desvio do preço médio ponderado por volume de transação (VWAP), para melhor entender o comportamento do mercado por trás do grande volume de transação.
Estratégia de Stop Loss Dinâmico: Implementação de stop loss dinâmico baseado na volatilidade, ajustando automaticamente a posição de stop loss à medida que a negociação se desenvolve na direção favorável, bloqueando parte dos lucros. Por exemplo, pode-se usar stop loss de rastreamento ou mover o stop loss para o preço de custo após a ruptura dos níveis críticos.
Filtros de correlação multivariadaPara variedades relevantes (por exemplo, índices de ações de futuros e de caixa, ouro e prata, etc.), adicionar indicadores de confirmação de variedades relevantes pode melhorar a qualidade do sinal. Quando várias variedades relevantes apresentam volume de negociação e comportamento de preços anormais ao mesmo tempo, o sinal pode ser mais confiável.
Otimização de aprendizagem de máquinaPor exemplo, uma árvore de decisão ou uma floresta aleatória pode ser usada para prever as melhores ações sob uma determinada característica de volume anormal.
Alteração da taxa de flutuaçãoAjustar os critérios de determinação do volume de transações anormais e os níveis de stop loss / stop loss de acordo com a atual situação de volatilidade do mercado. Em ambientes de alta volatilidade, aumentar a anormalidade pode determinar o limite e reduzir a distância de stop loss; em ambientes de baixa volatilidade, o contrário.
Adição de filtros básicosO Banco Central da Coreia do Sul (BCS) informou que o Banco Central da Coreia do Sul (BCS) está em negociações com o Banco Central do Japão (CBP) para o lançamento de novos dados econômicos.
A estratégia de captura de tendências de inversão de volume de negociação é um sistema de negociação quantitativa que se concentra no volume de negociação e no comportamento dos preços para capturar potenciais reversões, identificando mudanças no sentimento do mercado após o volume de negociação anormal. A estratégia define tecnicamente as condições de entrada e saída e as regras de gerenciamento de risco e inclui um mecanismo de filtragem de tempo inteligente para evitar períodos de baixa qualidade no mercado.
A vantagem central da estratégia reside na sua precisão na captura da “forma do indicador” do mercado, que geralmente cria oportunidades de reversão em curto prazo quando os participantes do mercado entram em grande quantidade e depois saem. A estratégia oferece uma forma disciplinada de negociação, localizando com precisão o preço limite em níveis críticos de preço e acompanhada de uma gestão racional de stop-loss.
No entanto, os usuários devem estar atentos aos riscos potenciais da estratégia em mercados de forte tendência, bem como à sensibilidade a eventos de notícias. A estratégia pode otimizar ainda mais a estabilidade e a adaptabilidade de seu desempenho, aumentando a confirmação de múltiplos períodos de tempo, ajustando dinamicamente os parâmetros e aumentando o mecanismo de gerenciamento de risco.
Em geral, a estratégia de captura de tendências de reversão de volume de negociação oferece aos comerciantes um sistema de negociação baseado no comportamento do mercado e nos princípios da psicologia, especialmente adequado para mercados voláteis e situações de turbulência de intervalos. Com a configuração racional e a otimização contínua, a estratégia tem potencial de se tornar uma ferramenta eficaz no portfólio de negociação.
/*backtest
start: 2024-05-13 00:00:00
end: 2025-05-11 08:00:00
period: 1h
basePeriod: 1h
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/
//@version=5
// Strategy Title Reflects Latest Logic
strategy(title="Middle Finger Trading Strategy",
shorttitle="Middle_Finger",
overlay=true,
pyramiding=0, // Only one entry at a time
default_qty_type=strategy.percent_of_equity,
default_qty_value=1, // Trade 1% of equity
commission_value=0.04, // Example commission (adjust as needed)
commission_type=strategy.commission.percent,
initial_capital = 10000, // Example starting capital
process_orders_on_close=false // Important for limit orders to potentially fill intra-bar
)
// --- Inputs ---
// Volume Settings Group
grp_vol = "Volume Settings"
float rthHugeVolMultiplier = input.float(3.0, title="1. RTH Huge Vol. Multiplier (> Avg)", minval=1.1, step=0.1, group=grp_vol, tooltip="Multiplier for core RTH (9:45-15:44 ET)")
float ethHugeVolMultiplier = input.float(5.0, title="2. ETH/Excluded Huge Vol. Multiplier (> Avg)", minval=1.1, step=0.1, group=grp_vol, tooltip="Multiplier for ETH and first/last 15min RTH (default 5x)")
int volLookback = input.int(20, title="3. Volume SMA Lookback", minval=1, group=grp_vol, tooltip="Lookback for calculating the filtered average volume (Used ONLY for identifying the HUGE spike)")
// Removed normalVolMultiplier as it's no longer used for entry confirmation
// Trend Settings Group
grp_trend = "Trend Settings"
int trendLookback = input.int(20, title="1. Trend SMA Lookback", minval=2, group=grp_trend, tooltip="Lookback period for the Simple Moving Average used to determine the trend before the spike")
// Risk Management Group
grp_risk = "Risk Management (SL/TP)"
string nqTargetTickerId = input.string("CME:NQ1!", title="1. Target Ticker ID for Fixed NQ Points", group=grp_risk, tooltip="Specify the exact Ticker ID (e.g., CME:NQ1!, TVC:NDX) for fixed SL/TP. Found in Symbol Info.")
float nqFixedStopPoints = input.float(20.0, title="2. Fixed SL Points (for Target Ticker)", group=grp_risk, minval=0.1, step=0.1)
float nqFixedTpPoints = input.float(50.0, title="3. Fixed TP Points (for Target Ticker)", group=grp_risk, minval=0.1, step=0.1)
// General SL/TP Settings (used if NOT the target ticker)
bool useAtrStops = input.bool(true, title="4. Use ATR for SL/TP (Other Tickers)?", group=grp_risk)
int atrLookback = input.int(14, title="5. ATR Lookback", group=grp_risk, inline="atr_other")
float atrStopMultiplier = input.float(2.0, title="6. ATR SL Multiplier", group=grp_risk, inline="atr_other", minval=0.1, step=0.1)
float atrTpMultiplier = input.float(4.0, title="7. ATR TP Multiplier", group=grp_risk, inline="atr_other", minval=0.1, step=0.1)
float fixedStopPoints = input.float(100.0, title="6. Fixed SL Points (Other Tickers)", group=grp_risk, inline="fixed_other", minval=1)
float fixedTpPoints = input.float(200.0, title="7. Fixed TP Points (Other Tickers)", group=grp_risk, inline="fixed_other", minval=1)
// Time Filter Settings Group
grp_time = "Time Filter (ET)"
bool enableEntryFilterRthEdges = input.bool(true, title="1. Filter Entries First/Last 15 Min RTH (ET)?", group=grp_time, tooltip="If checked, ignores entries from 9:30-9:44 ET and 15:45-15:59 ET. Avg Vol calc *always* filters these times, 4-6PM ET, and Sun pre-6PM ET.")
string targetTimezone = "America/New_York" // Specify Eastern Time zone
// --- Time Calculation Function ---
isTimeInSession(t, tz, sessionString) =>
not na(time(timeframe.period, sessionString, tz))
// --- Time Context Functions ---
getTimeContext(t, tz) =>
h = hour(t, tz)
m = minute(t, tz)
d = dayofweek(t, tz)
// Core RTH: 9:45 AM to 15:44 PM ET (Mon-Fri)
bool isCoreRTH = d >= dayofweek.monday and d <= dayofweek.friday and
((h == 9 and m >= 45) or (h >= 10 and h <= 14) or (h == 15 and m <= 44))
// Excluded RTH Edges: 9:30-9:44 ET and 15:45-15:59 ET (Mon-Fri)
bool isExcludedRTH = d >= dayofweek.monday and d <= dayofweek.friday and
((h == 9 and m >= 30 and m <= 44) or (h == 15 and m >= 45))
// After Hours Closed: 4:00 PM to 5:59 PM ET (Mon-Fri)
bool isAfterHoursClosed = d >= dayofweek.monday and d <= dayofweek.friday and
(h >= 16 and h < 18)
// Sunday Pre-Market: Sunday before 6:00 PM ET
bool isSundayPreMarket = d == dayofweek.sunday and h < 18
// Combine ALL periods where activity should be ignored or volume excluded from avg
bool isExcludedPeriod = isExcludedRTH or isAfterHoursClosed or isSundayPreMarket
[isCoreRTH, isExcludedRTH, isAfterHoursClosed, isSundayPreMarket, isExcludedPeriod]
// --- Get Time Context for Current and Previous Bar ---
[isCurrentBarCoreRTH, isCurrentBarExcludedRTH, isCurrentBarAfterHoursClosed, isCurrentBarSundayPreMarket, isCurrentBarExcludedPeriod] = getTimeContext(time, targetTimezone)
[isPreviousBarCoreRTH, isPreviousBarExcludedRTH, isPreviousBarAfterHoursClosed, isPreviousBarSundayPreMarket, isPreviousBarExcludedPeriod] = getTimeContext(time[1], targetTimezone)
// --- Calculations ---
// Volume Averaging: Exclude RTH edges, 4-6 PM ET, and Sunday Pre-6 PM ET ALWAYS
// This average is *only* used to define the huge volume spike threshold
bool excludeCurrentVolFromAvg = isCurrentBarExcludedPeriod
float volumeForAvgCalc = excludeCurrentVolFromAvg ? na : volume
float avgVolume = ta.sma(volumeForAvgCalc, volLookback)
// Dynamic Huge Volume Multiplier: Based on *previous* bar's time (Core RTH or not)
float activeHugeVolMultiplier = isPreviousBarCoreRTH ? rthHugeVolMultiplier : ethHugeVolMultiplier
// Use avgVolume[1] as current avgVolume excludes current bar, and we compare previous volume to avg *before* it
float hugeVolThreshold = nz(avgVolume[1]) * activeHugeVolMultiplier
// --- MODIFIED Volume Conditions ---
// 1. Check if the *previous* bar had huge volume compared to its preceding average
bool isHugeVolumePrevBar = volume[1] > hugeVolThreshold and hugeVolThreshold > 0
// 2. Check if the *current* bar's volume is simply lower than the previous (huge) bar's volume
bool isVolumeLowerThanSpike = volume < volume[1]
// Trend Condition
float priceSma = ta.sma(close, trendLookback)
// Ensure trend condition uses close[2] vs sma[2] (trend state *before* the spike bar)
bool isBullishTrendBeforeSpike = close[2] > nz(priceSma[2])
bool isBearishTrendBeforeSpike = close[2] < nz(priceSma[2])
// --- Entry Time Filtering ---
// Always filter After Hours Closed and Sunday Pre-Market.
// Optionally filter RTH Edges based on input.
bool shouldFilterRthEdges = enableEntryFilterRthEdges and isCurrentBarExcludedRTH
bool isIgnoreEntryTime = shouldFilterRthEdges or isCurrentBarAfterHoursClosed or isCurrentBarSundayPreMarket
// --- MODIFIED Base Conditions ---
// Uses the simplified `isVolumeLowerThanSpike` check
bool baseLongCondition = isBearishTrendBeforeSpike and isHugeVolumePrevBar and isVolumeLowerThanSpike
bool baseShortCondition = isBullishTrendBeforeSpike and isHugeVolumePrevBar and isVolumeLowerThanSpike
// Final Conditions (Apply Time Filter)
bool finalLongCondition = baseLongCondition and not isIgnoreEntryTime
bool finalShortCondition = baseShortCondition and not isIgnoreEntryTime
// --- Stop Loss & Take Profit Calculation (Conditional Logic) ---
// This part remains the same
float atrValue = ta.atr(atrLookback)
float tickValue = syminfo.mintick
int stopLossTicks = 100 // Default fallback SL ticks
int takeProfitTicks = 200 // Default fallback TP ticks
// Check if the current symbol matches the target ticker ID
bool isTargetTicker = str.upper(syminfo.tickerid) == str.upper(nqTargetTickerId) // Case-insensitive comparison
if (isTargetTicker and tickValue > 0)
// --- Target Ticker Logic (e.g., NQ Fixed Points) ---
float ticksPerPoint = 1.0 / tickValue
stopLossTicks := math.max(1, math.round(nqFixedStopPoints * ticksPerPoint))
takeProfitTicks := math.max(1, math.round(nqFixedTpPoints * ticksPerPoint))
else if tickValue > 0 // Use only if tickValue is valid
// --- Standard Logic (Other Tickers: ATR or Fixed) ---
float stopLossDistance = useAtrStops ? atrValue * atrStopMultiplier : fixedStopPoints * tickValue
float takeProfitDistance = useAtrStops ? atrValue * atrTpMultiplier : fixedTpPoints * tickValue
// Calculate ticks, ensuring it's at least 1 tick
stopLossTicks := na(stopLossDistance) ? 100 : math.max(1, math.round(stopLossDistance / tickValue))
takeProfitTicks := na(takeProfitDistance) ? 200 : math.max(1, math.round(takeProfitDistance / tickValue))
// Final check to ensure SL/TP are not na
stopLossTicks := nz(stopLossTicks, 100)
takeProfitTicks := nz(takeProfitTicks, 200)
// --- Strategy Execution ---
// Uses Limit Orders based on previous bar's low/high - Remains the same
float limitEntryPriceLong = low[1] // Target entry at the low of the huge volume bar
float limitEntryPriceShort = high[1] // Target entry at the high of the huge volume bar
if (finalLongCondition and strategy.position_size == 0)
strategy.cancel("S") // Cancel any pending short limit order first
strategy.entry("L", strategy.long, limit = limitEntryPriceLong)
strategy.exit("L SL/TP", from_entry="L", loss=stopLossTicks, profit=takeProfitTicks)
if (finalShortCondition and strategy.position_size == 0)
strategy.cancel("L") // Cancel any pending long limit order first
strategy.entry("S", strategy.short, limit = limitEntryPriceShort)
strategy.exit("S SL/TP", from_entry="S", loss=stopLossTicks, profit=takeProfitTicks)
// --- Plotting & Visuals ---
plot(avgVolume, title="Filtered Avg Volume", color=color.new(color.blue, 60), style=plot.style_line)
// Removed the plot for the normal volume threshold as it's no longer used
// Highlight huge volume bar (previous bar that triggered the signal)
bgcolor(isHugeVolumePrevBar[1] ? color.new(color.yellow, 85) : na, title="Huge Volume Bar [-1]")
// Highlight bars excluded from volume average calculation
bgcolor(excludeCurrentVolFromAvg ? color.new(color.teal, 90) : na, title="Vol Excluded from Avg Calc")
// Highlight bars where entries are ignored due to time filters
bgcolor(isIgnoreEntryTime and (baseLongCondition or baseShortCondition) ? color.new(color.gray, 75) : na, title="Entry Time Filtered Bar")
// --- MODIFIED Highlight base conditions met ---
// Reflects the updated base conditions using isVolumeLowerThanSpike
bgcolor(baseLongCondition and not isIgnoreEntryTime ? color.new(color.green, 90) : na, title="Base Long Condition Met")
bgcolor(baseShortCondition and not isIgnoreEntryTime ? color.new(color.red, 90) : na, title="Base Short Condition Met")
plot(priceSma, title="Trend SMA", color=color.gray)
// Plot SL/TP levels for visualization - Remains the same
var float entryPrice = na
var float slLevel = na
var float tpLevel = na
if (strategy.opentrades > 0 and strategy.opentrades[1] == 0) // Just entered a trade
entryPrice := strategy.opentrades.entry_price(0)
if (strategy.position_size > 0) // Long
slLevel := entryPrice - stopLossTicks * tickValue
tpLevel := entryPrice + takeProfitTicks * tickValue
else // Short
slLevel := entryPrice + stopLossTicks * tickValue
tpLevel := entryPrice - takeProfitTicks * tickValue
else if (strategy.opentrades == 0 and strategy.opentrades[1] > 0) // Position closed
entryPrice := na
slLevel := na
tpLevel := na
else if (strategy.opentrades > 0) // Position still open
entryPrice := strategy.opentrades.entry_price(0)
if (strategy.position_size > 0) // Long
slLevel := entryPrice - stopLossTicks * tickValue
tpLevel := entryPrice + takeProfitTicks * tickValue
else // Short
slLevel := entryPrice + stopLossTicks * tickValue
tpLevel := entryPrice - takeProfitTicks * tickValue
plot(strategy.opentrades > 0 ? slLevel : na, title="Stop Loss Level", color=color.red, style=plot.style_linebr)
plot(strategy.opentrades > 0 ? tpLevel : na, title="Take Profit Level", color=color.green, style=plot.style_linebr)
// Optional Debugging Plots
// plotchar(isHugeVolumePrevBar, "HugeVol[1]", "H", location.bottom, color.yellow, size=size.tiny)
// plotchar(isVolumeLowerThanSpike, "VolLow", "v", location.bottom, color.purple, size=size.tiny) // Changed char
// plotchar(finalLongCondition, "FinalLong", "L", location.top, color.green, size=size.tiny)
// plotchar(finalShortCondition, "FinalShort", "S", location.top, color.red, size=size.tiny)
// plot(finalLongCondition ? limitEntryPriceLong : na, "Long Limit Target", color.lime, style=plot.style_circles, linewidth=2)
// plot(finalShortCondition ? limitEntryPriceShort : na, "Short Limit Target", color.fuchsia, style=plot.style_circles, linewidth=2)