Repository navigation
fix(strategy-v2): align monthly timeframe duration, annualization periods, and driving frequency - #298
Merged
brokermr810 merged 1 commit intoOct 19, 2026
Conversation
…iods, and driving frequency - Add '1mo': 2_592_000 to FREQUENCY_SECONDS and TIMEFRAME_SECONDS - Map '1mo': '1M' in PROVIDER_TIMEFRAMES and add '1mo': 3600 poll interval - Define SUPPORTED_SUBSCRIPTION_FREQUENCIES to decouple subscription validation from duration lookup - Fix periods_per_year to return 12.0 for monthly timeframe instead of trading_days fallback - Correct driving_frequency comparison so 1w (604,800s) takes precedence over 1mo (2,592,000s) - Add comprehensive test suite in test_frequencies.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes monthly timeframe handling across Strategy API V2 and technical indicator alerts:
FREQUENCY_SECONDSandTIMEFRAME_SECONDSwith standard 30-day monthly bar duration (2,592,000 seconds).periods_per_yearreturning daily trading days (252 or 365.25) for monthly timeframes instead of 12.0.driving_frequencyresolution when comparing monthly against weekly intervals.SUPPORTED_SUBSCRIPTION_FREQUENCIES."1mo": "1M"in market dataPROVIDER_TIMEFRAMESand adds"1mo": 3600polling interval to indicator signal alerts.Mathematical & Architectural Formulation
1. Duration & Driving Frequency Hierarchy
In multi-timeframe analysis, the driving frequency$f_{\mathrm{driver}}$ represents the fastest subscribed bar frequency (i.e., minimal bar interval in seconds):
where$T(f)$ denotes the duration in seconds. Previously,
"1mo"was absent fromFREQUENCY_SECONDS, causingfrequency_seconds("1mo")to fall back to daily duration (86,400 s). Consequently:which incorrectly designated monthly as driving faster than weekly.
With$30 \times 86{,}400 = 2{,}592{,}000\text{ s}$ ), strict monotonic ordering holds:
"1mo": 2_592_000(standard financial convention of 30 days:2. Metric Annualization Factor ($N$ )
Annualized performance metrics (Sharpe ratio, Sortino ratio, annualized returns, and volatility) scale periodic returns$R_t$ with frequency-specific period factor $N$ (from
periods_per_year):For monthly returns,$N = 12.0$ . Previously, monthly frequencies (
"1mo","1month","monthly") fell through to the daily trading days count:With this fix,$12.0$ for monthly frequency across all asset classes.
periods_per_yearexplicitly returns3. Decoupling Subscription Validation from Duration Table
contract.pypreviously checked:This conflated the duration lookup table with Strategy API V2's execution subscription allowlist. While Strategy V2 explicitly restricts execution subscriptions to native bar frequencies up to weekly (
1mto1w, as documented in Section 6 ofSTRATEGY_DEV_GUIDE.mdand enforced bytest_contract_rejects_unsupported_monthly_subscription), general frequency utilities, market data loaders, and alert polling services need accurate monthly duration and annualization values.Introducing
SUPPORTED_SUBSCRIPTION_FREQUENCIES = ("1m", "3m", "5m", "15m", "30m", "1h", "4h", "1d", "1w")keepscompile_strategy_v2strictly compliant without corrupting duration and annualization lookups.Changes
backend_api_python/app/services/strategy_v2/frequencies.py:"1mo": 2_592_000toFREQUENCY_SECONDS.SUPPORTED_SUBSCRIPTION_FREQUENCIES."1week","1wk","w1", and"1month".periods_per_yearto return12.0when frequency is"1mo"or"1month".backend_api_python/app/services/strategy_v2/contract.py:SUPPORTED_SUBSCRIPTION_FREQUENCIESrather thanFREQUENCY_SECONDS.backend_api_python/app/services/strategy_v2/market_data.py:"1mo": 2592000toTIMEFRAME_SECONDS."1mo": "1M"toPROVIDER_TIMEFRAMES.backend_api_python/app/services/indicator_signal_alerts.py:"1mo": 3600to_poll_secondsmapping.backend_api_python/tests/test_frequencies.pycovering canonical aliases, duration hierarchy, driving frequency selection, annualization factors, and subscription set exclusion.backend_api_python/tests/test_indicator_signal_alerts.pyto verify polling intervals for"1mo","1MO", and"monthly".Test plan
backend_api_python/tests/test_frequencies.pypasses (6/6 tests)backend_api_python/tests/test_strategy_v2_multitimeframe.pypasses (14/14 tests)backend_api_python/tests/test_indicator_signal_alerts.pypasses (31/31 tests)python backend_api_python/scripts/backend_quality_check.pypasses with zero violationsAPI documentation (if routes/schemas changed)