# Architectural Plan & Standards

**Last Updated:** 2025-09-15

## 1. Problem Statement

While many refactoring efforts have been successful (e.g., MACD, Stochastics), attempts to make the **M2/M3** and **RSI Divergence** blocks timeframe-aware have repeatedly failed, causing significant performance regressions on the 1D baseline. This suggests a deeper issue than simple logic errors.

The core challenge is to find an architecture that allows us to achieve two conflicting goals simultaneously:
1.  **Preserve the strategy performance** currently seen on the 1D chart.
2.  **Enable multi-timeframe support** that allows for different threshold and length settings appropriate for each timeframe (12H, 8H, etc.).

This document outlines the strategic decisions and architectural patterns adopted to solve this challenge.

---

## 2. Strategic Decision: New Baseline and Architectural Standard

### 2.1. The "Multi-Call" Pattern

After extensive testing, a robust architectural pattern has been identified to solve the `simple int` vs. `series int` compiler issue for built-in `ta.*` functions. This "multi-call" pattern involves:
1.  Defining `simple int` inputs for each supported timeframe (e.g., `rsi_len_1D`, `rsi_len_12H`).
2.  Unconditionally calculating the indicator for each timeframe path (e.g., `rsi_1D = ta.rsi(close, rsi_len_1D)` and `rsi_12H = utils.f_dynamic_rsi(close, rsi_len_12H)`).
3.  Using a ternary operator or `switch` statement to select the final `series float` result based on the current chart's `timeframe.period`.

This pattern correctly works around the compiler's static analysis limitations and is now the official architectural standard for making components with `simple int` length requirements timeframe-aware.

### 2.2. The Decision: Prioritizing Maintainability Over Fragile Performance

*   **Observation:** Implementing the "multi-call" pattern for the RSI and ATR components resulted in a performance regression on the 1D chart, from a fragile 318k% to a stable **256,537%**.
*   **Hypothesis:** The original 318k% performance is an emergent property of a specific, linear script execution flow that is fundamentally incompatible with clean, modular, multi-timeframe code. Chasing this "perfect" but fragile state has proven to be a development dead-end.
*   **Baseline Performance Metrics (v2025.09.15):** (Note: Results from enabled conditions optimized for 1D performance)

    | Timeframe | Net Profit | Max Drawdown | Total Trades | Percent Profitable | 
    | :--- | :--- | :--- | :--- | :--- |
    | **1D** | 256,537% | 22.48% | 30 | 86.67% |
    | **12H** | 3,193% | 67.50% | 38 | 65.80% |
    | **8H** | 61.2% | 86.98% | 55 | 60% |
    | **6H** | -6.36% | 76.38% | 72 | 55.56% |
    | **4H** | 89.13% | 87.81% | 97 | 55.67% |
    

*   **Strategic Decision:** We will officially accept the **256,537%** performance as the **new "Golden Baseline"** for the 1D chart.
*   **Rationale:**
    1.  **The "Perfect" is the Enemy of the "Good":** A 256k% strategy that is well-structured, understandable, and extensible is more valuable long-term than a 318k% "black box" that breaks when touched.
    2.  **Unblocking Progress:** This decision allows us to move forward with high-value tasks, such as refactoring the M2/M3 logic, without being blocked by the regression-fixing cycle.
    3.  **Establishing a Standard:** The "multi-call" pattern is now our standard for implementing timeframe-aware logic.

This decision prioritizes the long-term health, clarity, and maintainability of the codebase over a fragile and likely irreproducible performance peak.

---

## 3. Phase 1: Component Refactoring (Completed)

This phase involved methodically refactoring components in `MainStrategy.pine` that used the old `timeframe_divisor` logic to our new "multi-call" architectural standard.

**Status:** All identified components have been successfully refactored, and the new 256k% baseline has been maintained.

*   **Completed:** ATR Stop Loss
*   **Completed:** RSI Divergence Block
*   **Completed:** Stochastic RSI Calculation
*   **Completed:** Stoch and RSI Range Filter
*   **Completed:** M2 MACD Calculations
*   **Completed:** Volatility Directional Exit
*   **Completed:** M3 Growth Rate ROC

---

## 4. Path Forward: M2/M3 Code Quality Refactoring (Phase 2)

With the rest of the strategy now on a stable, maintainable foundation, the next logical phase is to address the technical debt within the core M2/M3 logic block.

The detailed plan for this high-risk effort is documented in a separate file to allow for the necessary level of detail and methodical planning.

**See: [./refactoring_plan_M2.md](refactoring_plan_M2.md)**

---

## 5. Appendix: Analysis of Past Failures

It is critical to understand *why* previous, seemingly logical attempts to refactor have failed, as this analysis provides the justification for the "multi-call" pattern and our current architectural standard.

### 5.1. Why did "Walling Off" the 1D Logic Fail?

Our attempts to use an `if timeframe.period == "D"` block to isolate the 1D logic did not prevent performance regressions. This is a crucial point that needs a clear hypothesis.

*   **The "Execution Flow" Hypothesis:** The `v36` baseline's performance is not just a result of the code itself, but of the **exact, linear, top-to-bottom execution flow**. When we introduce an `if/else` block, we change this flow.
    *   **Example:** A variable like `rsid_osc` might be calculated inside the `if` block. Even if its value on the current bar is identical to the baseline, the Pine Script engine may now treat its *historical state* differently. When a downstream component (like the M2 block) accesses a historical value (e.g., `rsid_osc[1]`), it might receive a subtly different value than it would have in the original, purely linear script.
    *   **Conclusion:** This suggests that the stateful history of variables is as important as their current value. The "multi-call" pattern is the best solution as it avoids placing core calculations inside conditional blocks, thus better preserving the original execution flow.

### 5.2. Why is a Dual-Path Necessary for `ta.*` Functions?

*   **The "Dynamic Smoothing Trap" is the Primary Blocker:** The core issue remains that the RSI Divergence block's calculations rely on built-in `ta.ema`, `ta.stdev`, and `ta.dev`. To make their lengths timeframe-aware, we must replace them with our custom `f_dynamic_*` functions. As documented in the "Dynamic Smoothing Trap," these custom functions are not mathematically identical to TradingView's optimized versions.
*   **Hyptheses:** 
    1.  **One at a time:** A more careful, one-by-one approach would likely fail at the very first step. The moment we replace a built-in `ta.*` function in the 1D path, we introduce a performance regression. This reinforces the need for a "dual-path" architecture where the 1D logic *never* calls our custom dynamic functions. The "Library-Centric" model is a formal implementation of this dual-path concept. We supposedly attempted this but still had a peformance regression on the 1D baseline, how could this be? Perhaps the "dual-path" wasn't implemented correctly to really wall off the 1D logic?
    2.  **Convert series to simple:** Maybe the "series" variables that we are passing in aren't really series, they aren't really changing during the running of the script other than when the user changes the interval of the chart. Perhaps there's a way to implement these variables so that they are actually simple ints and not series ints?
    3.  **Carefully implement functionality identical 'ta.*' functions that accept series argument** Perhaps we could test and validate each of these implementations against the built in `ta.ema`, `ta.stdev`, and `ta.dev` implmentations so that there is no deviation in the results provided?
*   **Conclusion:** Hypothesis 2 is a non-starter due to Pine Script's type system. Hypothesis 3 (creating a perfect RMA-based dynamic RSI) is a valuable experiment but carries risk. The "multi-call" pattern (Hypothesis 1) provides the most reliable path forward by using the original `ta.*` functions for the 1D path and our custom dynamic functions for the intraday path.
