Skip to content

feat(llm-trade): enrich prompt with indicators, structure, and futures sentiment (#99)#104

Open
fray-cloud wants to merge 1 commit intodevfrom
feat/#99-llm-prompt-enrichment
Open

feat(llm-trade): enrich prompt with indicators, structure, and futures sentiment (#99)#104
fray-cloud wants to merge 1 commit intodevfrom
feat/#99-llm-prompt-enrichment

Conversation

@fray-cloud
Copy link
Copy Markdown
Owner

@fray-cloud fray-cloud commented May 2, 2026

Closes #99.

Three new prompt layers

  1. Inline-indicator enriched candles — every candle row now carries OHLCV + EMA20/50/200 + RSI14 + Bollinger(20, 2σ) + MACD(12/26/9) + ATR14. LLM reads trend alignment and momentum off a single row.
  2. structure summary — swing high/low over the prompt window + ATR-derived suggested SL distance.
  3. sentiment section — current funding rate + last 8 settlements + 7d avg, plus 24-point OI history with 24h % change.

Decisions (from grilling)

  • candleCount slider relabeled 프롬프트 캔들 수, range 30~120 (default 60). Backend always fetches MAX(220, prompt+50) so EMA200 is stable.
  • ISO 8601 timestamps truncated to interval precision (1m → minute, 1h → hour, 1d → date).
  • Funding/OI in their own sentiment section at natural cadence (funding 8h, OI 24×1h) — not inlined per candle.
  • Sentiment fetch failures degrade to null; system prompt instructs LLM to treat null as "missing, do not guess".

Modules

  • New @coin/indicators workspace package — single computeIndicators(candles) entry, owns IndicatorRow/IndicatorSeries types in @coin/types. Wraps technicalindicators so the rest of the codebase never imports it directly.
  • New BinanceRest methods: getFundingRateHistory, getCurrentFundingRate, getOpenInterest, getOpenInterestHistory.
  • New MarketContextService in api-server with Redis caching (funding 1h, OI 60s) and a deep buildMarketContext core that's pure modulo deps for unit testing.
  • LlmCliService.decide now takes marketContext directly; LlmTradesService.signal builds and forwards it.
  • TRADING_SYSTEM_PROMPT updated with full schema documentation.

Tests

  • @coin/indicators: 5 tests
  • buildMarketContext: 9 tests (prompt slicing, 220-candle floor, empty error, degraded sentiment, structure derivation, OI 24h change)
  • All existing api (66) + worker (13) + web (43) suites still green

🤖 Generated with Claude Code

Summary by Sourcery

Introduce an LLM-ready market context layer that enriches trading prompts with technical indicators, structural summaries, and futures sentiment, and refactor LLM trade signalling to consume this unified context.

New Features:

  • Add Binance REST methods and shared types for funding rate and open interest data to support futures sentiment.
  • Introduce a reusable @coin/indicators package to compute aligned OHLCV indicator series for candles.
  • Add a MarketContext builder and Nest service that assemble enriched candles, structure, and sentiment into a single prompt payload for the LLM.

Enhancements:

  • Update the trading system prompt and LLM CLI service to work with structured market context instead of raw candles, tightening TP/SL guidance to ATR-based structure.
  • Adjust the LLM trade form candle-count controls and logging to reflect the new prompt window semantics and EMA200 stability guarantees.

Tests:

  • Add unit tests for indicator computation and market context building, including sentiment degradation and structure/OI derivations.

…s sentiment (#99)

Closes #99.

Until now Claude received only OHLCV candles + symbol/interval — sufficient
for "raw price" reasoning but missing the trend strength, volatility, and
positioning signals a trading analyst actually uses. Signal quality was
inconsistent and indicators had to be inferred from scratch every call.

This PR adds three layers to the user prompt:

1. Inline-indicator enriched candles. Each candle row now carries EMA20/50/
   200, RSI14, Bollinger Bands(20, 2σ), MACD(12/26/9), and ATR14 alongside
   OHLCV — the LLM can read trend alignment and momentum off a single row.
2. structure summary — swing high/low over the prompt window plus an
   ATR-derived suggested SL distance, anchoring TP/SL placement to objective
   reference points instead of arbitrary % targets.
3. sentiment section — current funding rate + last 8 settlements + 7d avg,
   plus 24-point OI history with 24h % change. Tells the LLM how positioned
   the market is and whether new money is flowing in.

Schema decisions (from the grilling):
- candleCount slider relabeled "프롬프트 캔들 수", range 30-120 (default 60).
  Backend always fetches MAX(220, prompt+50) so EMA200 is stable regardless
  of what the user picks.
- Timestamps are ISO 8601 truncated to interval precision (1m → minute,
  1h → hour, 1d → date) so the LLM can recognize sessions and the 8h funding
  cycle without arithmetic.
- Funding/OI live in their own `sentiment` section at their natural cadence
  (funding 8h, OI 24×1h) rather than being inlined per candle — avoids
  repeating the same funding value 60 times on a 5m window.
- Sentiment fetch failures degrade to null instead of failing the signal.
  System prompt instructs the LLM to treat null as "missing, do not guess."

Modules
- New @coin/indicators workspace package — wraps technicalindicators behind
  a single computeIndicators(candles) entry point. Aligned IndicatorRow per
  candle with explicit nulls during warmup. Owned types live in @coin/types.
- New BinanceRest methods: getFundingRateHistory, getCurrentFundingRate,
  getOpenInterest, getOpenInterestHistory. All public (no signature).
- New MarketContextService in api-server — orchestrates fetch + compute +
  structure + sentiment with Redis caching (funding 1h, OI 60s) and a deep
  buildMarketContext core that's pure modulo deps for unit testing.
- LlmCliService.decide now accepts a marketContext directly; LlmTradesService.
  signal builds and forwards it. The DB log captures schema metadata so old
  vs new prompts are distinguishable.
- Updated TRADING_SYSTEM_PROMPT documents the new schema (field names, units,
  null semantics) and tells the model to calibrate TP/SL to structure.atrPct
  and structure.suggestedSlPct.

Tests
- @coin/indicators: 5 tests — alignment with input length, warmup nulls,
  RSI behavior on trending vs flat closes, BB middle = SMA20, ATR positive.
- buildMarketContext: 9 tests — prompt window slicing, 220-candle floor,
  empty-candles error, degraded sentiment on adapter throws, structure
  swing/ATR derivation, OI 24h change.
- All existing api (66) + worker (13) + web (43) suites still green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented May 2, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
coin-web Ready Ready Preview, Comment May 2, 2026 6:24am

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented May 2, 2026

Reviewer's Guide

Adds a new indicators package and market-context pipeline so LLM trades use enriched candles, structural stats, and futures sentiment, plus new Binance futures data endpoints and a retuned trading system prompt and UI slider.

Sequence diagram for enriched LLM trade signal flow

sequenceDiagram
  actor User
  participant WebApp
  participant ApiServer as ApiServer_LlmTradesController
  participant LlmTradesService
  participant MarketContextService
  participant Redis
  participant BinanceRest
  participant LlmCliService
  participant ClaudeCli as Claude_CLI

  User->>WebApp: Submit LLM trade form
  WebApp->>ApiServer: POST /llm-trades/signal
  ApiServer->>LlmTradesService: signal(userId,dto)
  LlmTradesService->>LlmTradesService: getDecryptedToken(userId)
  LlmTradesService->>MarketContextService: build(symbol,interval,promptCandleCount)

  MarketContextService->>BinanceRest: getCandles(symbol,interval,fetchCount>=max(220,prompt+50))
  MarketContextService->>Redis: GET funding:history:symbol
  Redis-->>MarketContextService: cache hit or miss
  alt funding history cache miss
    MarketContextService->>BinanceRest: getFundingRateHistory(symbol,8)
    MarketContextService->>Redis: SET funding:history:symbol
  end
  MarketContextService->>Redis: GET funding:current:symbol
  alt funding current cache miss
    MarketContextService->>BinanceRest: getCurrentFundingRate(symbol)
    MarketContextService->>Redis: SET funding:current:symbol
  end
  MarketContextService->>Redis: GET oi:history:symbol:period
  alt oi history cache miss
    MarketContextService->>BinanceRest: getOpenInterestHistory(symbol,period,24)
    MarketContextService->>Redis: SET oi:history:symbol:period
  end
  MarketContextService->>MarketContextService: computeIndicators(candles)
  MarketContextService->>MarketContextService: derive structure and sentiment
  MarketContextService-->>LlmTradesService: MarketContext

  LlmTradesService->>LlmCliService: decide(oauthToken,marketContext)
  LlmCliService->>ClaudeCli: runClaudeCli(TRADING_SYSTEM_PROMPT,JSON.stringify(marketContext))
  ClaudeCli-->>LlmCliService: raw JSON decision
  LlmCliService->>LlmCliService: parse and validate using last candle close
  LlmCliService-->>LlmTradesService: LlmDecision

  LlmTradesService->>LlmTradesService: compute entryPrice from last candle
  LlmTradesService->>ApiServer: save llmDecisionLog
  LlmTradesService-->>ApiServer: decision + entryPrice + marketContext
  ApiServer-->>WebApp: HTTP response
  WebApp-->>User: Show signal, TP, SL, context
Loading

Class diagram for indicators package and indicator types

classDiagram
  class Candle {
    <<interface>>
    +string exchange
    +string symbol
    +string interval
    +string open
    +string high
    +string low
    +string close
    +string volume
    +number timestamp
  }

  class IndicatorRow {
    <<interface>>
    +number nullable ema20
    +number nullable ema50
    +number nullable ema200
    +number nullable rsi14
    +number nullable bbUpper
    +number nullable bbMiddle
    +number nullable bbLower
    +number nullable macd
    +number nullable macdSignal
    +number nullable macdHistogram
    +number nullable atr14
  }

  class IndicatorSeries {
    <<interface>>
    +IndicatorRow[] rows
  }

  class ComputeOptions {
    <<interface>>
    +number[3] nullable emaPeriods
    +number nullable rsiPeriod
    +number nullable bbPeriod
    +number nullable bbStdDev
    +number nullable macdFast
    +number nullable macdSlow
    +number nullable macdSignal
    +number nullable atrPeriod
  }

  class IndicatorsModule {
    +computeIndicators(candles:Candle[],opts:ComputeOptions) IndicatorSeries
  }

  Candle --> IndicatorSeries : input
  IndicatorSeries --> IndicatorRow : contains
  IndicatorsModule --> Candle : reads
  IndicatorsModule --> IndicatorSeries : returns
  IndicatorsModule --> IndicatorRow : populates
Loading

Class diagram for market context, services, and Binance futures sentiment

classDiagram
  class FundingRateRecord {
    <<interface>>
    +string symbol
    +number fundingTime
    +string fundingRate
  }

  class OpenInterestSnapshot {
    <<interface>>
    +string symbol
    +string openInterest
    +number timestamp
  }

  class OpenInterestPoint {
    <<interface>>
    +string symbol
    +string sumOpenInterest
    +string sumOpenInterestValueUsdt
    +number timestamp
  }

  class IndicatorRow {
    <<interface>>
    +number nullable ema20
    +number nullable ema50
    +number nullable ema200
    +number nullable rsi14
    +number nullable bbUpper
    +number nullable bbMiddle
    +number nullable bbLower
    +number nullable macd
    +number nullable macdSignal
    +number nullable macdHistogram
    +number nullable atr14
  }

  class EnrichedCandleRow {
    <<interface>>
    +string t
    +string o
    +string h
    +string l
    +string c
    +string v
    +number nullable ema20
    +number nullable ema50
    +number nullable ema200
    +number nullable rsi14
    +number nullable bbUpper
    +number nullable bbMiddle
    +number nullable bbLower
    +number nullable macd
    +number nullable macdSignal
    +number nullable macdHistogram
    +number nullable atr14
  }

  class StructureSummary {
    <<interface>>
    +number nullable swingHigh
    +string nullable swingHighAt
    +number nullable swingLow
    +string nullable swingLowAt
    +number nullable atrPct
    +number nullable suggestedSlPct
  }

  class FundingSentiment {
    <<interface>>
    +string nullable current
    +number nullable nextFundingTime
    +SettlementPoint[] lastSettlements
    +number nullable avg7d
  }

  class SettlementPoint {
    <<type>>
    +string t
    +string rate
  }

  class OpenInterestSentiment {
    <<interface>>
    +number nullable currentUsdt
    +number nullable change24hPct
    +OiHistoryPoint[] history
  }

  class OiHistoryPoint {
    <<type>>
    +string t
    +number oi
  }

  class SentimentSummary {
    <<interface>>
    +FundingSentiment nullable fundingRate
    +OpenInterestSentiment nullable openInterest
  }

  class MarketContext {
    <<interface>>
    +string symbol
    +string interval
    +EnrichedCandleRow[] candles
    +StructureSummary structure
    +SentimentSummary sentiment
  }

  class BuildOptions {
    <<interface>>
    +string symbol
    +string interval
    +number promptCandleCount
  }

  class BuildDeps {
    <<interface>>
    +fetchCandles(symbol:string,interval:string,count:number) Promise~Candle[]~
    +fetchFundingHistory(symbol:string,limit:number) Promise~FundingRateRecord[]~
    +fetchCurrentFunding(symbol:string) Promise~FundingCurrent~
    +fetchOpenInterestHistory(symbol:string,period:string,limit:number) Promise~OpenInterestPoint[]~
  }

  class FundingCurrent {
    <<type>>
    +string symbol
    +string lastFundingRate
    +number nextFundingTime
  }

  class MarketContextBuilder {
    +MIN_FETCH_COUNT:number
    +buildMarketContext(opts:BuildOptions,deps:BuildDeps) Promise~MarketContext~
    +formatTimestamp(epochMs:number,interval:string) string
  }

  class MarketContextService {
    +build(symbol:string,interval:string,promptCandleCount:number) Promise~MarketContext~
    -cached~T~(key:string,ttlSec:number,fetcher:Function) Promise~T~
  }

  class IExchangeRest {
    <<interface>>
    +getFundingRateHistory(symbol:string,limit?:number) Promise~FundingRateRecord[]~
    +getCurrentFundingRate(symbol:string) Promise~FundingCurrent~
    +getOpenInterest(symbol:string) Promise~OpenInterestSnapshot~
    +getOpenInterestHistory(symbol:string,period:string,limit?:number) Promise~OpenInterestPoint[]~
  }

  class BinanceRest {
    +getFundingRateHistory(symbol:string,limit?:number) Promise~FundingRateRecord[]~
    +getCurrentFundingRate(symbol:string) Promise~FundingCurrent~
    +getOpenInterest(symbol:string) Promise~OpenInterestSnapshot~
    +getOpenInterestHistory(symbol:string,period:string,limit?:number) Promise~OpenInterestPoint[]~
  }

  class LlmCliService {
    +decide(oauthToken:string,marketContext:MarketContext) Promise~LlmDecision~
    -buildUserPrompt(input:LlmDecisionInput) string
    -parse(cliStdout:string,marketContext:MarketContext) LlmDecision
  }

  class LlmTradesService {
    +signal(userId:string,dto:RequestSignalDto) Promise~LlmDecisionWithContext~
  }

  class LlmDecisionInput {
    <<type>>
    +string oauthToken
    +MarketContext marketContext
  }

  class LlmDecisionWithContext {
    <<type>>
    +string signal
    +string takeProfitPrice
    +string stopLossPrice
    +string entryPrice
    +MarketContext marketContext
  }

  FundingSentiment --> SettlementPoint : uses
  OpenInterestSentiment --> OiHistoryPoint : uses
  SentimentSummary --> FundingSentiment : contains
  SentimentSummary --> OpenInterestSentiment : contains
  MarketContext --> EnrichedCandleRow : candles
  MarketContext --> StructureSummary : structure
  MarketContext --> SentimentSummary : sentiment

  EnrichedCandleRow --|> IndicatorRow : extends

  MarketContextBuilder --> BuildOptions : input
  MarketContextBuilder --> BuildDeps : input
  MarketContextBuilder --> MarketContext : output
  MarketContextBuilder --> EnrichedCandleRow : builds
  MarketContextBuilder --> StructureSummary : computes
  MarketContextBuilder --> SentimentSummary : computes

  MarketContextService --> MarketContextBuilder : calls_buildMarketContext
  MarketContextService --> BinanceRest : uses

  BinanceRest ..|> IExchangeRest

  LlmCliService --> MarketContext : reads
  LlmTradesService --> MarketContextService : uses
  LlmTradesService --> LlmCliService : uses
  LlmTradesService --> MarketContext : returns_in_response
Loading

File-Level Changes

Change Details Files
Introduce @coin/indicators package to compute standard TA indicators and expose them via shared types.
  • Add IndicatorRow/IndicatorSeries types to @coin/types representing per-candle indicator values with warmup nulls.
  • Implement computeIndicators wrapper around technicalindicators to compute EMA20/50/200, RSI14, Bollinger(20,2σ), MACD(12/26/9), and ATR14 aligned to candles.
  • Add unit tests in the indicators package to validate warmup behavior and basic indicator properties, plus TS/ Vitest config and packaging metadata.
packages/types/src/exchange.ts
packages/indicators/src/compute.ts
packages/indicators/src/compute.test.ts
packages/indicators/src/index.ts
packages/indicators/package.json
packages/indicators/tsconfig.json
packages/indicators/vitest.config.ts
Build a MarketContext pipeline that fetches candles, computes indicators, derives structure, and enriches with futures sentiment, with Redis caching.
  • Implement pure buildMarketContext that over-fetches candles (>=220) for stable EMA200, inlines indicators into candles, derives swing highs/lows and ATR-based SL suggestions, and attaches funding/OI sentiment with graceful degradation on failure.
  • Define MarketContext-related types (enriched candle rows, structure summary, funding/open interest sentiment) and timestamp truncation helper respecting interval precision.
  • Implement MarketContextService using BinanceRest and Redis caching for funding and open interest history, and wire it into LlmTradesModule and LlmTradesService to build marketContext for each signal request.
  • Add unit tests for buildMarketContext covering prompt slicing, minimum fetch, empty candles error, degraded sentiment, structure fields, OI 24h change, and timestamp formatting.
apps/api-server/src/llm-trades/market-context/build-market-context.ts
apps/api-server/src/llm-trades/market-context/build-market-context.test.ts
apps/api-server/src/llm-trades/market-context/market-context.service.ts
apps/api-server/src/llm-trades/market-context/market-context.types.ts
apps/api-server/src/llm-trades/llm-trades.module.ts
apps/api-server/src/llm-trades/llm-trades.service.ts
apps/api-server/package.json
Extend BinanceRest and IExchangeRest to expose futures funding and open interest data used by sentiment layer.
  • Add FundingRateRecord, OpenInterestSnapshot, and OpenInterestPoint types under @coin/types for futures sentiment.
  • Implement BinanceRest methods to fetch funding rate history, current funding rate (premium index), open interest snapshot, and open interest history, including error handling and response mapping.
  • Extend IExchangeRest interface to declare the new futures market data methods.
packages/exchange-adapters/src/binance/binance.rest.ts
packages/types/src/exchange.ts
packages/exchange-adapters/src/interfaces/exchange-rest.ts
Rework LLM integration to consume structured MarketContext JSON and log enriched context in decisions.
  • Change LlmCliService.decide/buildUserPrompt/parse to accept MarketContext instead of raw candles, sending it as JSON and deriving lastClose from enriched candles.
  • Update LlmTradesService.signal to build MarketContext via MarketContextService, compute entry price from enriched candles, and log prompt metadata including indicator/sentiment enrichment.
  • Adjust the trading system prompt to document the new candles/structure/sentiment schema, null-handling rules, and volatility-calibrated TP/SL constraints and reasoning hints.
apps/api-server/src/llm/llm-cli.service.ts
apps/api-server/src/llm-trades/llm-trades.service.ts
apps/api-server/src/llm/prompts/trading-system.ts
Tighten web UI controls for LLM candle count with prompt-focused labeling and bounds aligned to backend behavior.
  • Change default candleCount to 60, constrain slider between 30 and 120 with clamping on input change, and clarify label text (프롬프트 캔들 수) and tooltip describing backend over-fetch for indicators.
  • Add helper copy explaining that indicators are computed on 220+ candles while the slider only controls rows visible to the LLM.
apps/web/src/components/llm-trade/llm-trade-form.tsx

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The 7d funding-rate average in computeAvg7d is computed from whatever fetchFundingHistory returns (currently limited to 8 records), which contradicts the inline comment about 21 settlements over 7 days; consider either increasing the history limit or updating the semantics/comment so the LLM isn’t misled by a very short-window “7d” average.
  • MarketContextService directly instantiates Redis and BinanceRest rather than using Nest DI, which makes configuration and testing harder; consider injecting these as providers so you can more easily swap endpoints/credentials or mock them in higher-level tests.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The 7d funding-rate average in `computeAvg7d` is computed from whatever `fetchFundingHistory` returns (currently limited to 8 records), which contradicts the inline comment about 21 settlements over 7 days; consider either increasing the history limit or updating the semantics/comment so the LLM isn’t misled by a very short-window “7d” average.
- `MarketContextService` directly instantiates `Redis` and `BinanceRest` rather than using Nest DI, which makes configuration and testing harder; consider injecting these as providers so you can more easily swap endpoints/credentials or mock them in higher-level tests.

## Individual Comments

### Comment 1
<location path="apps/api-server/src/llm-trades/market-context/build-market-context.ts" line_range="189-190" />
<code_context>
+  interval: string,
+  deps: BuildDeps,
+): Promise<OpenInterestSentiment | null> {
+  // OI history granularity scales with the user's candle interval, capped at 1h
+  // to keep the series readable (24 points = 24h window at 1h granularity).
+  const period = oiPeriodFor(interval);
+  try {
</code_context>
<issue_to_address>
**issue:** The OI period selection comment doesn’t match the actual behavior for sub-hour intervals.

Since oiPeriodFor returns '5m' for 1m/3m/5m intervals, the 24 points only span ~2h, so change24hPct is not actually a 24h change for those cases. Consider either always using a fixed '1h' period so the metric is truly 24h, or renaming/adjusting downstream usage and prompt text to reflect that this is a shorter-window OI change on low timeframes.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +189 to +190
// OI history granularity scales with the user's candle interval, capped at 1h
// to keep the series readable (24 points = 24h window at 1h granularity).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: The OI period selection comment doesn’t match the actual behavior for sub-hour intervals.

Since oiPeriodFor returns '5m' for 1m/3m/5m intervals, the 24 points only span ~2h, so change24hPct is not actually a 24h change for those cases. Consider either always using a fixed '1h' period so the metric is truly 24h, or renaming/adjusting downstream usage and prompt text to reflect that this is a shorter-window OI change on low timeframes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant