Стратегия торговли импульсным трендом настроений свечей, основанная на количественных индикаторах

CEI ADX RSI MACD VOLUME SMA
Дата создания: 2025-02-21 13:23:51 Последнее изменение: 2025-02-21 13:23:51
Копировать: 1 Количество просмотров: 361
2
Подписаться
319
Подписчики

Стратегия торговли импульсным трендом настроений свечей, основанная на количественных индикаторах Стратегия торговли импульсным трендом настроений свечей, основанная на количественных индикаторах

Обзор

Стратегия основана на графическом анализе рыночных настроений, для количественного анализа рыночной психологии с помощью трех основных колебателей: колебатель неохоты, колебатель страха и колебатель жадности. Стратегия объединяет динамику и трендовые показатели, а также объединяет подтверждение объема, чтобы создать полную торговую систему. Стратегия подходит для трейдеров, которые хотят идентифицировать высоковероятные торговые возможности с помощью анализа рыночных настроений.

Стратегический принцип

В основе стратегии лежит построение трёх эмоциональных осцилляторов, анализирующих различные формы рисунка:

  1. Неожиданный колебатель - измерение неопределенности рынка с помощью крестозвезды и вихревой формы
  2. Страшные колебатели - отслеживают пустые эмоции с помощью метеоритов, подвесных линий и поглощающих форм.
  3. Жадность-ассилятор - для выявления многоголовых эмоций с помощью солнечных лучей на голове, шнура на шее, поглощения змеи и три белых солдата

Средние значения этих трех колебателей составляют индекс эмоций криптовалюты (CEI). Когда CEI преодолевает различные пороги, это вызывает сигналы о многомерной торговле и подтверждается количеством сделок.

Стратегические преимущества

  1. Систематизированный эмоциональный анализ - преобразование субъективного анализа в объективный показатель с помощью количественной диаграммы
  2. Управление рисками - включает в себя механизмы, такие как максимальные сроки хранения позиций, стоп-стоп и период охлаждения
  3. Гибкий механизм восстановления - когда сделка терпит убытки, стратегия пытается восстановиться, преодолевая равновесие
  4. Многорыночная применимость - может применяться для нескольких рынков, таких как акции, валюты и криптовалюты
  5. Высокая надежность сигнала - повышение точности с помощью подтверждения объема транзакций и проверки множества технических показателей

Стратегический риск

  1. Чувствительность параметров - настройки различных порогов требуют тщательного тестирования и оптимизации
  2. Зависимость от рыночной конъюнктуры - возможные ошибочные сигналы на рынке во время колебаний
  3. Риск скольжения - риск возможного исполнения в менее ликвидном рынке
  4. Риск чрезмерной торговли - необходимо установить разумный период охлаждения, чтобы избежать частых торгов
  5. Системный риск - вероятность больших убытков при крупных рыночных событиях

Направление оптимизации стратегии

  1. Динамические понижения - автоматическая корректировка различных понижений в зависимости от рыночных колебаний
  2. Классификация состояния рынка - механизм идентификации повышенных тенденций и рыночных колебаний
  3. Оптимизация машинного обучения - оптимизация параметров с помощью алгоритмов машинного обучения
  4. Улучшение управления рисками - добавление модулей управления капиталом и контроля позиций
  5. Фильтрация сигналов - интеграция дополнительных технических показателей для фильтрации ложных сигналов

Подвести итог

Это инновационная стратегия, объединяющая технический анализ с количественной торговлей. Благодаря систематизированному анализу эмоций и строгому управлению рисками, стратегия способна предоставлять трейдерам надежные торговые сигналы. Несмотря на то, что существует определенный простор для оптимизации, основная структура стратегии является прочной и подходит для дальнейшей разработки и применения на рынке.

Исходный код стратегии
/*backtest
start: 2024-03-09 18:40:00
end: 2025-02-19 08:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"Binance","currency":"SOL_USDT"}]
*/

//@version=6
strategy("Candle Emotion Index Strategy", shorttitle="CEI Strategy", overlay=true)

// User Inputs
length = input.int(14, title="Lookback Period", minval=1)
dojiThreshold = input.float(0.1, title="Doji Threshold", minval=0.01, maxval=0.5)
spinningTopThreshold = input.float(0.3, title="Spinning Top Threshold", minval=0.1, maxval=0.5)
shootingStarThreshold = input.float(0.5, title="Shooting Star Threshold", minval=0.1, maxval=1.0)
hangingManThreshold = input.float(0.5, title="Hanging Man Threshold", minval=0.1, maxval=1.0)
engulfingThreshold = input.float(0.5, title="Engulfing Threshold", minval=0.1, maxval=1.0)
marubozuThreshold = input.float(0.9, title="Marubozu Threshold", minval=0.5, maxval=1.0)
hammerThreshold = input.float(0.5, title="Hammer Threshold", minval=0.1, maxval=1.0)
threeWhiteSoldiersThreshold = input.float(0.5, title="Three White Soldiers Threshold", minval=0.1, maxval=1.0)

// Volume Multiplier Input
volumeMultiplier = input.float(1.5, title="Volume Multiplier", minval=1.0)

// Cooldown Period Input
cooldownPeriod = input.int(10, title="Cooldown Period (Candles)", minval=1)

// Maximum Holding Period Inputs
maxHoldingPeriod = input.int(20, title="Maximum Holding Period (Candles)", minval=1)
lossHoldingPeriod = input.int(10, title="Loss Exit Holding Period (Candles)", minval=1)
lossThreshold = input.float(0.02, title="Loss Threshold (as % of Entry Price)", minval=0.01, maxval=1.0)

// --- Indecision Oscillator Functions ---
isDoji(open, close, high, low, threshold) =>
    bodySize = math.abs(close - open)
    rangeSize = high - low
    bodySize / rangeSize < threshold

isSpinningTop(open, close, high, low, threshold) =>
    bodySize = math.abs(close - open)
    rangeSize = high - low
    bodySize / rangeSize < threshold and bodySize / rangeSize >= dojiThreshold

indecisionOscillator() =>
    var float dojiScore = 0.0
    var float spinningTopScore = 0.0
    for i = 1 to length
        if isDoji(open[i], close[i], high[i], low[i], dojiThreshold)
            dojiScore := dojiScore + 1.0
        if isSpinningTop(open[i], close[i], high[i], low[i], spinningTopThreshold)
            spinningTopScore := spinningTopScore + 1.0
    dojiScore := dojiScore / length
    spinningTopScore := spinningTopScore / length
    (dojiScore + spinningTopScore) / 2

// --- Fear Oscillator Functions ---
isShootingStar(open, close, high, low, threshold) =>
    bodySize = math.abs(close - open)
    upperWick = high - math.max(open, close)
    lowerWick = math.min(open, close) - low
    upperWick / bodySize > threshold and lowerWick < bodySize

isHangingMan(open, close, high, low, threshold) =>
    bodySize = math.abs(close - open)
    upperWick = high - math.max(open, close)
    lowerWick = math.min(open, close) - low
    lowerWick / bodySize > threshold and upperWick < bodySize

isBearishEngulfing(open, close, openPrev, closePrev, threshold) =>
    bodySize = math.abs(close - open)
    prevBodySize = math.abs(closePrev - openPrev)
    close < openPrev and open > closePrev and bodySize / prevBodySize > threshold

fearOscillator() =>
    var float shootingStarScore = 0.0
    var float hangingManScore = 0.0
    var float engulfingScore = 0.0
    for i = 1 to length
        if isShootingStar(open[i], close[i], high[i], low[i], shootingStarThreshold)
            shootingStarScore := shootingStarScore + 1.0
        if isHangingMan(open[i], close[i], high[i], low[i], hangingManThreshold)
            hangingManScore := hangingManScore + 1.0
        if isBearishEngulfing(open[i], close[i], open[i+1], close[i+1], engulfingThreshold)
            engulfingScore := engulfingScore + 1.0
    shootingStarScore := shootingStarScore / length
    hangingManScore := hangingManScore / length
    engulfingScore := engulfingScore / length
    (shootingStarScore + hangingManScore + engulfingScore) / 3

// --- Greed Oscillator Functions ---
isMarubozu(open, close, high, low, threshold) =>
    bodySize = math.abs(close - open)
    totalRange = high - low
    bodySize / totalRange > threshold

isHammer(open, close, high, low, threshold) =>
    bodySize = math.abs(close - open)
    lowerWick = math.min(open, close) - low
    upperWick = high - math.max(open, close)
    lowerWick / bodySize > threshold and upperWick < bodySize

isBullishEngulfing(open, close, openPrev, closePrev, threshold) =>
    bodySize = math.abs(close - open)
    prevBodySize = math.abs(closePrev - openPrev)
    close > openPrev and open < closePrev and bodySize / prevBodySize > threshold

isThreeWhiteSoldiers(open, close, openPrev, closePrev, openPrev2, closePrev2, threshold) =>
    close > open and closePrev > openPrev and closePrev2 > openPrev2 and close > closePrev and closePrev > closePrev2

greedOscillator() =>
    var float marubozuScore = 0.0
    var float hammerScore = 0.0
    var float engulfingScore = 0.0
    var float soldiersScore = 0.0
    for i = 1 to length
        if isMarubozu(open[i], close[i], high[i], low[i], marubozuThreshold)
            marubozuScore := marubozuScore + 1.0
        if isHammer(open[i], close[i], high[i], low[i], hammerThreshold)
            hammerScore := hammerScore + 1.0
        if isBullishEngulfing(open[i], close[i], open[i+1], close[i+1], engulfingThreshold)
            engulfingScore := engulfingScore + 1.0
        if isThreeWhiteSoldiers(open[i], close[i], open[i+1], close[i+1], open[i+2], close[i+2], threeWhiteSoldiersThreshold)
            soldiersScore := soldiersScore + 1.0
    marubozuScore := marubozuScore / length
    hammerScore := hammerScore / length
    engulfingScore := engulfingScore / length
    soldiersScore := soldiersScore / length
    (marubozuScore + hammerScore + engulfingScore + soldiersScore) / 4

// --- Final Calculations ---
indecision = indecisionOscillator()
fear = fearOscillator()
greed = greedOscillator()

// Calculate the average of the three oscillators
averageOscillator = (indecision + fear + greed) / 3

// --- Combined Strategy Logic ---
var float entryPriceLong = na
var float entryPriceShort = na
var int holdingPeriodLong = 0
var int holdingPeriodShort = 0
var int cooldownCounter = 0

// Buy Signal Logic for Long and Short
longBuySignal = ta.crossover(averageOscillator, 0.1)
shortBuySignal = ta.crossover(averageOscillator, 0.2)

// Calculate average volume over the lookback period
avgVolume = ta.sma(volume, length)

// Take Profit Conditions
longTakeProfitCondition = close > open and volume > avgVolume * volumeMultiplier
shortTakeProfitCondition = close < open and volume > avgVolume * volumeMultiplier

// Buy Logic for Long Positions
if longBuySignal and strategy.position_size == 0 and cooldownCounter <= 0
    entryPriceLong := close
    strategy.entry("Long Entry", strategy.long)
    cooldownCounter := cooldownPeriod
    holdingPeriodLong := 0

// Increment holding period if in a long position
if strategy.position_size > 0
    holdingPeriodLong := holdingPeriodLong + 1

// Sell Logic for Long Positions
if longTakeProfitCondition and strategy.position_size > 0 and close > entryPriceLong
    strategy.close_all()
    cooldownCounter := cooldownPeriod

if holdingPeriodLong >= maxHoldingPeriod and strategy.position_size > 0 and close >= entryPriceLong
    strategy.close_all()
    cooldownCounter := cooldownPeriod

if holdingPeriodLong >= lossHoldingPeriod and strategy.position_size > 0 and close < entryPriceLong * (1 - lossThreshold)
    strategy.close_all()
    cooldownCounter := cooldownPeriod

// Short Logic for Short Positions
if shortBuySignal and strategy.position_size == 0 and cooldownCounter <= 0
    entryPriceShort := close
    strategy.entry("Short Entry", strategy.short)
    cooldownCounter := cooldownPeriod
    holdingPeriodShort := 0

// Increment holding period if in a short position
if strategy.position_size < 0
    holdingPeriodShort := holdingPeriodShort + 1

// Cover Logic for Short Positions
if shortTakeProfitCondition and strategy.position_size < 0 and close < entryPriceShort
    strategy.close_all()
    cooldownCounter := cooldownPeriod

if holdingPeriodShort >= maxHoldingPeriod and strategy.position_size < 0 and close <= entryPriceShort
    strategy.close_all()
    cooldownCounter := cooldownPeriod

if holdingPeriodShort >= lossHoldingPeriod and strategy.position_size < 0 and close > entryPriceShort * (1 + lossThreshold)
    strategy.close_all()
    cooldownCounter := cooldownPeriod

// Decrement the cooldown counter each candle
if cooldownCounter > 0
    cooldownCounter := cooldownCounter - 1