Page 4 of 4
Re: Golden Week and Thanksgiving: Holiday-Specific Liquidity Patterns
Posted: Wed Oct 07, 2026 6:45 pm
by PTScalper
Why this architecture scales:
By decoupling the detection of the market state from the reaction to it, you maintain strict Separation of Concerns. The indicator acts as a pure sensor, parsing the microstructure. The cBot acts as the brain, interpreting those bitwise flags to dynamically shift its trading parameters without needing to recalculate ATR or check calendar dates itself.
Re: Golden Week and Thanksgiving: Holiday-Specific Liquidity Patterns
Posted: Wed Oct 07, 2026 6:46 pm
by PTScalper
Pine Script v5 does not support C#-style bitwise operators or true Enums. However, it introduces User-Defined Types (UDTs), which allow us to create a custom object that holds the exact granular state of the market.
By packaging the calendar and microstructure conditions into a single MarketState object, your Pine Script strategy can read the specific flags (e.g., if state.isXmas) just like the cBot, rather than relying on a tangled web of global boolean variables.
Re: Golden Week and Thanksgiving: Holiday-Specific Liquidity Patterns
Posted: Wed Oct 07, 2026 6:46 pm
by PTScalper
Here is the
"Pro" architecture translated into a complete Pine Script v5 Strategy. It separates the Sensors (detecting liquidity) from the Execution (the trading logic).
Code: Select all
//@version=5
strategy("Liquidity-Aware Strategy PRO", overlay=true, calc_on_every_tick=true, margin_long=100, margin_short=100)
// =============================================================================
// 1. INPUTS & CONFIGURATION
// =============================================================================
grp_cal = "Calendar Filters"
showXmas = input.bool(true, "Christmas to NY", group=grp_cal)
showGold = input.bool(true, "Golden Week", group=grp_cal)
showUS = input.bool(true, "US Thanksgiving", group=grp_cal)
showAug = input.bool(false, "August Drain", group=grp_cal)
grp_mic = "Microstructure Filters"
useVol = input.bool(true, "Volatility Drop", group=grp_mic)
useSpr = input.bool(true, "Spread Spike Proxy", group=grp_mic)
atrLen = input.int(14, "ATR Length", group=grp_mic)
baseLen = input.int(100, "Baseline SMA Length", group=grp_mic)
dropPct = input.float(70.0, "Vol Drop Threshold (%)", group=grp_mic) / 100
gapPct = input.float(15.0, "Max Gap (% of ATR)", group=grp_mic) / 100
bodyPct = input.float(25.0, "Max Body Size (% of Total)", group=grp_mic) / 100
// =============================================================================
// 2. USER-DEFINED TYPE (The "Struct/Enum" Replacement)
// =============================================================================
// This object will hold the exact state of the current bar
type MarketState
bool isXmas
bool isGolden
bool isUSHoliday
bool isAugust
bool isVolDrop
bool isSpreadSpike
bool anyDanger // Master flag
// =============================================================================
// 3. CORE SENSOR FUNCTION (The Microservice)
// =============================================================================
// Global Series calculations (must be calculated on every bar outside functions)
currentAtr = ta.atr(atrLen)
baselineAtr = ta.sma(currentAtr, baseLen)
detectMarketState(atr, bAtr) =>
// Calendar Logic
bool xmas = showXmas and ((month == 12 and dayofmonth >= 24) or (month == 1 and dayofmonth <= 2))
bool gold = showGold and ((month == 4 and dayofmonth >= 29) or (month == 5 and dayofmonth <= 5))
bool us = showUS and (month == 11 and ((dayofweek == dayofweek.thursday and dayofmonth >= 22 and dayofmonth <= 28) or (dayofweek == dayofweek.friday and dayofmonth >= 23 and dayofmonth <= 29)))
bool aug = showAug and (month == 8)
// Microstructure Logic
bool volDrop = useVol and (atr < (bAtr * dropPct))
gapSize = math.abs(open - close[1])
candleRange = high - low
candleBody = math.abs(close - open)
bool gapSpike = gapSize > (atr * gapPct)
bool wickSpike = (candleRange > (atr * 0.8)) and (candleBody < (candleRange * bodyPct))
bool sprSpike = useSpr and (gapSpike or wickSpike)
// Master flag
bool danger = xmas or gold or us or aug or volDrop or sprSpike
// Return the packed object
MarketState.new(xmas, gold, us, aug, volDrop, sprSpike, danger)
// Instantiate the state object for the current bar
state = detectMarketState(currentAtr, baselineAtr)
// =============================================================================
// 4. VISUALIZATION HIERARCHY
// =============================================================================
// Resolves the highest priority color based on the state object
color bgColor = na
if state.isXmas
bgColor := color.new(color.red, 85)
else if state.isGolden
bgColor := color.new(color.orange, 85)
else if state.isUSHoliday
bgColor := color.new(color.blue, 85)
else if state.isAugust
bgColor := color.new(color.purple, 90)
else if state.isVolDrop
bgColor := color.new(color.gray, 80)
else if state.isSpreadSpike
bgColor := color.new(color.yellow, 70)
bgcolor(bgColor, title="Danger Zone BG")
// =============================================================================
// 5. STRATEGY EXECUTION & GRANULAR FILTERING
// =============================================================================
// Example moving average crossover for standard entry logic
fastMA = ta.sma(close, 9)
slowMA = ta.sma(close, 21)
longCondition = ta.crossover(fastMA, slowMA)
shortCondition = ta.crossunder(fastMA, slowMA)
// --- The Granular Logic ---
// 1. HARD REJECTS (Close positions and refuse new ones)
if state.isXmas or state.isGolden
// Tier-1 Liquidity is offline. Liquidate everything.
strategy.close_all(comment="Holiday Shutdown")
// 2. SOFT REJECTS (Suspend new entries, but let existing trades run)
else if state.isSpreadSpike
// A sudden whip-saw occurred. Do nothing this bar.
// We don't close existing trades here so we don't realize slippage.
pass = true // Placeholder to skip entry block
// 3. ADAPTIVE EXECUTION (Normal vs Low Volatility)
else
if longCondition
if state.isVolDrop
// Enter with a tighter target because market lacks momentum
strategy.entry("Long (Range)", strategy.long, comment="Low Vol Long")
strategy.exit("Exit Range", "Long (Range)", profit=100) // 10 pips
else
// Standard trend entry
strategy.entry("Long (Trend)", strategy.long, comment="Trend Long")
if shortCondition
if state.isVolDrop
strategy.entry("Short (Range)", strategy.short, comment="Low Vol Short")
strategy.exit("Exit Range", "Short (Range)", profit=100)
else
strategy.entry("Short (Trend)", strategy.short, comment="Trend Short")
Re: Golden Week and Thanksgiving: Holiday-Specific Liquidity Patterns
Posted: Wed Oct 07, 2026 6:47 pm
by PTScalper
Why this architecture scales in Pine Script:
Zero Spaghetti Code: Instead of writing if (isXmas or isGolden or isUSHoliday) and not isVolDrop all over your execution logic, you simply query the state object (e.g., if state.isSpreadSpike).
Single Pass Calculation: The calendar and math formulas are evaluated exactly once per bar inside detectMarketState(). The execution block then reads the cached object properties, making the script highly optimized for backtesting thousands of trades.
Actionable Context: The strategy doesn't just know that it shouldn't trade; it knows why. It can actively command a strategy.close_all() during Golden Week, while choosing to hold open positions—but suspend new entries—during a localized spread spike.