
Стратегия захвата трендов по объему сделок - это количественный метод торговли, основанный на необычном объеме сделок и ценовом поведении, предназначенный для выявления ключевых моментов, когда рынок может изменить направление. В основе этой стратегии лежит поиск K-линий с значительно более высоким, чем средний, объемом сделок, и принятие решений о торговле в соответствии с предыдущим направлением тренда при подтверждении снижения объема сделок.
Основные принципы этой стратегии основаны на обратном тренде после необычного объема торгов на рынке. Конкретная логика действий следующая:
Выявление аномального объема транзакцийСистема обнаруживает, имеет ли предыдущая K-линия значительно более высокий, чем средний, объем сделок. В обычные торговые периоды (RTH) объем сделок должен быть в 3 раза больше, чем средний объем сделок за последнее время (регулируемый); в послеобеденные или специальные периоды (ETH) - более чем в 5 раз.
Подтверждение снижения объемов торгов: текущая линия K должна иметь меньший объем транзакций, чем предыдущая линия K с аномальной мощностью, что указывает на то, что крупные транзакции закончились.
Определение направления: определение направления тренда путем сравнения цены закрытия до K-линии сверхнормального объема торгов с отношением к SMA (простой движущейся средней).
Сигнал обратного входа:
Вход в систему:
Управление рискамиВ зависимости от особенностей разных сортов, система предлагает два варианта параметров остановки/остановки:
Фильтр времени: Стратегия может выборочно фильтровать торговые сигналы в течение первых и последних 15 минут RTH и всегда фильтровать сигналы в период после закрытия торгового дня (в 4-6 часов вечера) и в период до закрытия торгового дня в воскресенье.
Поймать ключевые моментыСтратегия ориентирована на захват рыночных поворотных точек, которые сопровождаются аномальными объемами сделок, которые обычно представляют собой значительные изменения в настроениях рынка и обеспечивают более высокие шансы на выигрыш.
Точное место входа: повышение точности входа, обеспечивая торговлю на технически важном уровне цен, с использованием ограничительных цен в высоких/низких точках по линии K с необычным объемом торгов.
Количество самостоятельной идентификацииСтратегия: Динамическая корректировка критериев определения объема необычных сделок в зависимости от различных торговых периодов (обычные торговые часы против после закрытия / особых периодов), чтобы соответствовать реальным условиям рынка.
Гибкое управление рисками: Предоставляет опции остановки/остановки на основе фиксированного балла и ATR, индивидуальные настройки могут быть сделаны в зависимости от характеристик и волатильности различных сортов.
Интеллектуальный фильтр времени: автоматически идентифицирует и отфильтровывает низкую ликвидность и нестабильные периоды торговли, чтобы избежать ложных сигналов, которые легко появляются вблизи открытия и закрытия рынка.
Ясный визуальный отзывСтратегия: обеспечивает интуитивно понятные визуальные указания на графике, включая необычные торговые K-линии, трендовые SMA-линии, стоп-стоп-линии, для удобства мониторинга и анализа.
Автоматизация исполненияПри выполнении условий система автоматически выполняет ограничительные и стоп-стоп-установки, сокращая вмешательство человека и поддерживая дисциплину торговли.
Риск ложного проникновенияДля смягчения этого риска можно рассмотреть возможность добавления подтверждающих показателей, таких как подтверждение RSI опережения/перепродажи или требование продолжительности прорыва.
Влияние новостных событийКлючевые экономические данные или объявления компаний могут привести к аномальному объему торгов, но эти реакции обычно продолжаются дольше, чем немедленно. Рекомендуется приостановить стратегию или добавить фильтрующие условия до и после публикации важных экономических данных.
Риск изменения рыночной среды: В условиях сильной тенденции торговля в обратном направлении может столкнуться с сохраняющимся неблагоприятным движением цен. Можно рассмотреть возможность добавления долгосрочных фильтров тенденций, чтобы избежать обратной операции в условиях сильной тенденции.
Риск невыполнения ценовой лимиты: Если цена не достигнет установленного предельного уровня на следующей K-линии, торговый сигнал может быть недействителен. Можно рассмотреть возможность установления максимального срока действия или перейти к исполнению по рыночной цене при определенных условиях.
Риск низкой ликвидности: Несмотря на то, что в стратегии включена функция временной фильтрации, некоторые сорта могут испытывать проблемы с недостаточной ликвидностью в определенные периоды времени. Рекомендуется адаптировать ограничения на время торгов в соответствии с особенностями торговых сортов.
Риски оптимизации параметров: Избыточная оптимизация параметров стратегии может привести к тому, что они будут плохо работать в будущем, если они не соответствуют историческим данным. Следует обеспечить, чтобы параметры были в разумных пределах, и проверить устойчивость стратегии путем внештатной проверки.
Подтверждение многократного цикла: добавление фильтра трендов с более высокими временными циклами, чтобы обеспечить более высокую выигрышную вероятность в более крупном трендовом направлении. Например, можно проверить направление тренда солнечной линии и играть только в том случае, если он соответствует тренду солнечной линии.
Оценка качества объемов сделокПомимо чистого объема, можно рассмотреть возможность увеличения количества сделок с помощью качественной оценки, например, отклонения от средней цены, взвешенной по объему сделок (VWAP), чтобы лучше понять поведение рынка за большим количеством сделок.
Динамическая стоп-стратегия: реализация динамического стоп-показателя, основанного на волатильности, автоматическая корректировка стоп-позиции по мере того, как торговля развивается в благоприятном направлении, блокирование части прибыли. Например, можно использовать следящий стоп или перемещать стоп-показатель до стоимости после прорыва критического уровня.
Фильтрация корреляцииДля соответствующих видов (например, фондовый индекс, фьючерсы и наличные, золото и серебро и т. д.) добавление подтверждающих индикаторов соответствующих видов повышает качество сигнала. Сигнал может быть более надежным, когда несколько соответствующих видов одновременно имеют аномальный объем торговли и поведение цен.
Оптимизация машинного обучения: Анализ наиболее успешных аномальных моделей объема сделок в исторических данных с помощью алгоритмов машинного обучения, динамическая корректировка условий и параметров входа. Например, можно использовать деревья решений или случайные леса для прогнозирования наилучших действий при данных аномальных характеристиках объема сделок.
Корректировка колебаний: в зависимости от текущего состояния волатильности рынка корректировать критерии определения аномального объема торговли и уровень остановки / остановки. В условиях высокой волатильности повышение аномального объема может определить порог и снизить расстояние остановки; в условиях низкой волатильности наоборот.
Добавить базовые фильтрыВ день публикации важных экономических данных или в день ежеквартального финансового отчета следует сезонно корректировать параметры стратегии или приостановить торговлю, чтобы избежать ложных сигналов, вызванных помехами в новостях.
Стратегия захвата обратных тенденций - это количественная торговая система, ориентированная на объем торгов и ценовое поведение, для захвата потенциальных обратных точек путем выявления изменений в настроении рынка после аномального объема торгов. Стратегия определяет технически четкие условия входа, выхода и правила управления рисками и включает в себя интеллектуальный механизм временной фильтрации, чтобы избежать периодов низкого качества рынка.
Ключевое преимущество стратегии заключается в том, что она точно фиксирует “междулежащие формы” рынка, которые часто создают краткосрочные возможности для реверса при массовом притоке и последующем выводе участников рынка. Эта стратегия обеспечивает дисциплинированный метод торговли, путем четкого определения цены на ключевых уровнях и в сочетании с разумным управлением стоп-стоп-убытком.
Однако пользователям следует обращать внимание на потенциальные риски стратегии на рынках с сильными тенденциями, а также на ее чувствительность к новостным событиям. С помощью увеличения подтверждения многократных временных циклов, динамической корректировки параметров и усиления механизмов управления рисками стратегия может еще больше оптимизировать свою стабильность и адаптивность.
В целом, стратегия захвата обратных тенденций в объеме торгов предоставляет трейдерам торговую систему, основанную на принципах поведения рынка и психологии, которая особенно подходит для волатильных рынков и колебаний в диапазоне. При разумной настройке и постоянной оптимизации эта стратегия может стать эффективным инструментом в торговом портфеле.
/*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)