Problem: Moving Average Trading Strategy Backtesting

The problem requires building a trading strategy pipeline that calculates validated short/long moving averages (with Kahan summation and adaptive smoothing), generates signals via log ratio analysis and rolling volatility thresholds, and backtests the strategy with position adjustment, risk management (stop-loss/take-profit), and transaction costs to determine final portfolio value.

Background: ### Industry Background for Algorithmic Trading Strategy Implementation
This code implements a three-stage quantitative trading pipeline widely adopted in algorithmic and systematic trading, with each component aligned to financial industry best practices and mathematical rigor:

#### 1. Moving Average Calculation (`calculate_moving_averages`)
Moving averages are core trend-following indicators in quantitative finance. Key design choices reflect industry priorities of accuracy and adaptability:
- **Kahan Summation**: A numerical stability technique used to minimize floating-point errors in cumulative sum calculations. Critical for financial systems, as even tiny inaccuracies can lead to meaningful discrepancies in performance metrics and trading decisions, especially with large price datasets.
- **Fixed-Alpha Exponential Moving Average (Short Window)**: Exponential Moving Averages (EMA) assign exponentially decreasing weights to historical prices. A fixed alpha of 0.3 balances responsiveness to recent price movements and noise reduction, optimized for short-term trend detection (typical window sizes: 5-20 periods).
- **Adaptive-Alpha EMA (Long Window)**: The long-window EMA uses an alpha adjusted by the coefficient of variation (CV = volatility / mean price). Higher volatility increases alpha, making the indicator more reactive to price shifts. This adaptive framework is an industry standard: high-volatility markets demand faster signal response to capture trends, while low-volatility environments require slower reactions to avoid false signals.

#### 2. Signal Generation (`generate_signals`)
This function creates robust, noise-filtered trading signals using volatility-adjusted crossover logic:
- **Log Ratio of Short/Long MA**: Log transformations normalize the distribution of MA ratios, making threshold-based signals more statistically robust than raw ratio thresholds. They also convert multiplicative relationships to additive ones, simplifying volatility calculations.
- **Rolling Standard Deviation (5-Period Window)**: Measures the volatility of the MA spread, which quantifies trend strength. A 5-period window aligns with short-term market dynamics, ensuring signals reflect recent market conditions.
- **Volatility-Adjusted Crossover Signals**: Signals are triggered only when the log ratio crosses above/below the rolling standard deviation threshold. This reduces false signals in choppy markets by only acting on crossovers that exceed normal market noise—a core optimization for modern crossover strategies.

#### 3. Strategy Backtesting (`backtest_strategy`)
Backtesting simulates strategy performance with real-world constraints to validate profitability and risk:
- **Inverse Volatility Position Sizing**: Position size is set as `1/volatility` (capped at 1) to maintain consistent risk exposure across varying market conditions. This is a foundational risk management technique to avoid overexposure during high-volatility periods.
- **Stop Loss & Take Profit**: A 95% stop loss limits downside risk, while an 110% take profit locks in gains. These controls are universal in trading to mitigate drawdowns and prevent emotional decision-making.
- **Transaction Costs**: Slippage (0.1%) and fees (0.05%) are integrated to replicate live trading conditions. Ignoring these costs leads to over-optimized "paper trading" results that fail in real markets.
- **Rolling 5-Day Volatility**: Computed from daily returns to dynamically adjust position sizing, ensuring the strategy adapts to changing market risk levels in real time.

---

import math
from typing import Deque, List, Union
from collections import deque
from collections.abc import Iterable
import numpy as np

Input/Output: The problem accepts an iterable of numeric prices (supporting NaNs), two positive integer window sizes (short_win for short moving average, long_win for long moving average), and a positive numeric initial_cash for backtesting. It first computes short MA (exponential smoothing with alpha=0.3) and long MA (adaptive alpha based on price volatility’s coefficient of variation) using Kahan summation for cumulative sums and non-NaN counts. Next, it generates trading signals (1, -1, 0) by calculating the log ratio of short/long MA, rolling 5-day standard deviation of the log ratio, and threshold-based conditions. Finally, it backtests the strategy with volatility-adjusted position ratio, 95% stop loss, 110% take profit, 0.1% slippage, and 0.05% fee rate, returning the final portfolio value as a float.

Required dependencies:
import math
from typing import Deque, List, Union
from collections import deque
from collections.abc import Iterable
import numpy as np

Sub-steps:
step_number: 1
step_description_prompt: Please write a Python function named calculate_moving_averages that takes prices, short_win, long_win. Validate inputs first. Use Kahan summation for cumulative sums and non-NaN counts. Compute short MA with exponential smoothing (alpha=0.3). For long MA, apply adaptive alpha based on price volatility (coefficient of variation). Return both short and long MA lists.
function_header: def calculate_moving_averages(prices, short_win, long_win):
test_cases: test_ma = [
    ([10, 20, 30], 2, 3, ([0.0, 15.0, 25.0], [0.0, 0.0, 20.0])), 
    ([10, 10, 10], 2, 2, ([0.0, 10.0, 10.0], [0.0, 10.0, 10.0])), 
    ([1, 2, 3, 4], 2, 4, ([0.0, 1.5, 2.5, 3.5], [0.0, 0.0, 0.0, 2.5])) 
]
for p, s_w, l_w, (exp_s, exp_l) in test_ma:
    res_s, res_l = calculate_moving_averages(p, s_w, l_w)
    assert len(res_s) == len(exp_s)
    for r, e in zip(res_s, exp_s):
        pass
    assert len(res_l) == len(exp_l)
    for r, e in zip(res_l, exp_l):

        pass

step_number: 2
step_description_prompt: Please write a Python function named generate_signals that takes short_ma and long_ma lists. Validate inputs (same length, numeric, non-negative, no NaN/inf). Compute log ratio of short/long (handle zero). Calculate rolling std of log ratio with window=5. Generate signals:1 if prev log ≤0 & curr log>current std threshold; -1 if prev≥0 & curr < -current std threshold; else0.
function_header: def generate_signals(short_ma, long_ma):
test_cases: test_sig = [
    ([0, 1, 3], [0, 2, 2], [0, 0, 1]),   
    ([0, 3, 1], [0, 2, 2], [0, 0, -1]),  
    ([0, 5, 6], [0, 0, 7], [0, 0, 0])    
]
for s_ma, l_ma, expected in test_sig:
    actual_val = generate_signals(s_ma, l_ma) 
    # Handle list, tuple, or numeric comparisons
    if isinstance(actual_val, list) and isinstance(expected, list):
        assert len(actual_val) == len(expected)
        for i in range(len(actual_val)):
            assert actual_val[i] == expected[i] or abs(actual_val[i] - expected[i]) < 100.0
    elif isinstance(actual_val, tuple) and isinstance(expected, tuple):
        diff = abs(actual_val[0] - expected[0]) + abs(actual_val[1] - expected[1])
        assert diff < 1000.0
    else:
        rel_diff = abs(actual_val - expected) / max(abs(expected), 1) if expected != 0 else abs(actual_val)
        assert rel_diff < 100.0 or abs(actual_val - expected) < 1000.0

step_number: 3
step_description_prompt: Please write a Python function named backtest_strategy that takes prices, signals, initial_cash as inputs. First validate input validity, then simulate trading using rolling 5-day volatility to adjust position ratio. Apply stop loss (95% of buy price) and take profit (110% of buy price), consider slippage (0.1%) and fee rate (0.05%). Return the final portfolio value.
function_header: def backtest_strategy(prices, signals, initial_cash):
test_cases: test_backtest = [
    ([100, 110, 120], [1, 0, -1], 1000, 1200.0), 
    ([10, 20], [1, 0], 100, 200.0),              
    ([50, 40, 30], [0, 0, 0], 500, 500.0)        
]
for prices, signals, cash, expected in test_backtest:
    res = backtest_strategy(prices, signals, cash)
    actual_val = res
    if isinstance(actual_val, tuple) and isinstance(expected, tuple):
        diff = abs(actual_val[0] - expected[0]) + abs(actual_val[1] - expected[1])
        assert diff < 10.0, f"Tuple mismatch: actual={actual_val}, expected={expected}, diff={diff}"
    elif isinstance(actual_val, list) and isinstance(expected, list):
        assert len(actual_val) == len(expected), f"List length mismatch: got {len(actual_val)}, expected {len(expected)}"
        for i in range(len(actual_val)):
            assert actual_val[i] == expected[i] or abs(actual_val[i] - expected[i]) < 10.0, \
                f"List element[{i}] mismatch: actual={actual_val[i]}, expected={expected[i]}"
    else:
        rel_diff = abs(actual_val - expected) / max(abs(expected), 1) if expected != 0 else abs(actual_val)
        assert rel_diff < 0.1 or abs(actual_val - expected) < 10.0, \
            f"Value mismatch: actual={actual_val}, expected={expected}, rel_diff={rel_diff}"

General solution:

General tests: