Aladdin Crypto Pair Strategy (MACD Enhanced) - Process Flow

This document outlines the logical steps of the aladdin_crypto_pair_strategy_macd backtesting process, based on the provided flowchart.

1. Input Validation & Preparation

  1. Receive Inputs:
    • Primary data: analysis_results (output from Gini_lamp_analyze_crypto_ratio, containing prices, ratio, Z-score, initial signals).
    • Strategy Parameters: MACD settings (Fast, Slow, Signal periods), Initial Capital, Transaction Fee %, Stop Loss %.
  2. Validate Inputs:
    • Check if analysis_results has the expected structure and columns.
    • Verify parameter types and ranges (e.g., capital > 0, fee >= 0, stop_loss > 0).
    • If validation fails, the process stops here with an error.
  3. Identify Required Columns: Locate columns for Ticker 1 Price, Ticker 2 Price, Ratio (Ticker2/Ticker1), Z-Score, and Signal within the input data.
  4. Check Data Sufficiency: Ensure there are enough data rows to calculate the MACD indicator based on the specified periods.
    • If data is insufficient, the process stops here with an error.
  5. Log Initial Setup: Record the starting parameters and the crypto pair being analyzed.

2. Indicator Calculation

  1. Sort Data: Ensure the input data is sorted chronologically by date/time.
  2. Calculate MACD: Compute the MACD (Moving Average Convergence Divergence) indicator, including its signal line and histogram, specifically on the Ticker2/Ticker1 price ratio.
  3. Combine Data: Merge the calculated MACD values back into the main dataframe, aligned by date.
  4. Derive Signals: Create simplified signal columns based on indicators:
    • Z-Score Direction: 1 if Z-Score suggests Long Ratio (e.g., Z < threshold), -1 if Short Ratio (e.g., Z > threshold), 0 if Neutral (Hold). (Logic depends on specific Z-score strategy from input)
    • MACD Crossover: 1 if MACD line crosses above Signal line (Bullish Crossover), -1 if MACD crosses below Signal line (Bearish Crossover), 0 otherwise.

3. Backtest State Initialization

  1. Initialize State Variables: Set up variables to track the backtest's state throughout the simulation:
    • cash_usd = Initial Capital
    • qty_ticker1 = 0
    • qty_ticker2 = 0
    • position_type = 0 (0: Flat, 1: Long Ratio, -1: Short Ratio)
    • entry_equity = NA (Equity value at the time of trade entry)
    • entry_date = NA
    • entry_price_T1 / entry_price_T2 = NA
  2. Initialize Equity Curve DataFrame: Create an empty structure to store daily portfolio values (date, cash, quantities, prices, total equity).
  3. Initialize Trades Log: Create an empty list or structure to record details of each completed trade.

4. Simulation Loop Setup

  1. Determine Loop Start Index: Find the first row in the data where all required prices and calculated signals (MACD, Z-Score) are valid (not NA).
    • If no valid starting point is found, the process stops here.
  2. Initialize Equity Curve Pre-Loop: Fill the equity curve DataFrame with the initial capital value for all dates *before* the determined loop start date.
  3. Log Simulation Start: Record the date and row index where the simulation loop begins.

5. Simulation Loop (Daily Iteration)

The following steps are performed for each day/row from the determined start index to the end of the data:

  1. Get Current Day Data: Extract Date, Price Ticker 1, Price Ticker 2, Z-Signal, MACD Cross signal for the current row.
  2. Validate Prices: Check if both Ticker 1 and Ticker 2 prices for the current day are valid (Not NA, greater than 0).
    • If prices are invalid: Skip all trading logic for this day, carry forward the previous day's state (cash, quantities), record the state, update equity curve, and proceed to the next day.
  3. Calculate Start-of-Day (SoD) Equity: Calculate the portfolio value *before* any potential trades for the day: SoD Equity = cash_usd + (qty_ticker1 * current_price_T1) + (qty_ticker2 * current_price_T2).
  4. Decision: Currently In a Position? (position_type != 0)
    • IF YES (In Position): Proceed to Stop Loss Check
      1. Calculate Current Trade PnL %: PnL = (SoD Equity / entry_equity) - 1.
      2. Decision: PnL % < -Stop Loss %?
        • IF YES (Stop Loss Triggered):
          1. ACTION: Trigger Stop Loss
          2. Liquidate Position: Simulate closing both legs (sell T1 if long, buy T1 if short; buy T2 if short, sell T2 if long) at current prices.
          3. Apply Exit Fees to both legs.
          4. Update cash_usd.
          5. Log Trade Details: Record the exit in the Trades Log with "Stop Loss" as the reason.
          6. Reset Position State: Set position_type = 0, clear entry variables (entry_equity, entry_date, etc.).
          7. Proceed directly to End-of-Day recording.
        • IF NO (Stop Loss Not Triggered): Proceed to Exit Condition Check.
      3. Decision: Exit Conditions Met? (e.g., Z-Signal reverses direction OR MACD gives a counter-signal like bearish cross while long ratio / bullish cross while short ratio)
        • IF YES (Exit Triggered):
          1. ACTION: Trigger Regular Exit
          2. Liquidate Position: Simulate closing both legs at current prices.
          3. Apply Exit Fees to both legs.
          4. Update cash_usd.
          5. Log Trade Details: Record the exit in the Trades Log with the reason (e.g., "Z Reversal", "MACD Cross").
          6. Reset Position State: Set position_type = 0, clear entry variables.
          7. Proceed directly to End-of-Day recording.
        • IF NO (Hold Position): No action needed, proceed to End-of-Day recording.
    • IF NO (Currently Flat - position_type == 0): Proceed to Entry Condition Check
      1. Decision: Entry Conditions Met? (e.g., Z-Signal indicates entry AND MACD confirms direction OR Z-Signal flips strongly)
        • IF YES (Entry Triggered):
          1. ACTION: Trigger Entry
          2. Record Entry Equity: Store the current SoD Equity as entry_equity.
          3. Allocate Capital: Determine dollar amount for each leg (e.g., 50% of current equity per leg).
          4. Apply Entry Fees: Deduct calculated fees for *both* legs from cash_usd.
          5. Determine Entry Type: Based on signals (Z-score, MACD), decide whether to go Long Ratio (Buy T2, Sell T1) or Short Ratio (Sell T2, Buy T1). Update position_type (1 or -1).
          6. Calculate Quantities: Based on allocated capital (less fees) and current prices, calculate qty_ticker1 (will be negative if shorting T1) and qty_ticker2 (will be negative if shorting T2). Ensure one is positive and one is negative.
          7. Update Position State: Record entry_date, entry_price_T1, entry_price_T2.
          8. Log Entry: Print or log details of the new position opened.
          9. Proceed to End-of-Day recording.
        • IF NO (Stay Flat): No action needed, proceed to End-of-Day recording.
  5. Record End-of-Day (EoD) State: Store the final cash_usd, qty_ticker1, and qty_ticker2 for the current day *after* any trades and fee deductions.
  6. Calculate Final EoD Equity: Recalculate the total portfolio equity using the EoD state variables and current day's prices. EoD Equity = final_cash_usd + (final_qty_T1 * price_T1) + (final_qty_T2 * price_T2).
  7. Update Equity Curve DataFrame: Record the EoD state (cash, quantities, prices, calculated equity) for the current date in the equity curve dataframe.
  8. Loop End Check: Is this the last row of data?
    • IF NO: Proceed to the next day/row (Go back to step 1 of Section 5).
    • IF YES: Exit the loop and proceed to Post-Processing.

6. Post-Processing & Performance Metrics

  1. Combine Trades Log: Consolidate the list of individual trade records into a single DataFrame.
  2. Fill Equity Curve NAs: Handle any potential missing values in the equity curve (e.g., forward fill).
  3. Filter Equity Curve: Ensure the equity curve data only covers the actual simulation period (from loop start date onwards).
  4. Check Valid Equity Data: Verify that the final equity curve contains valid numerical data.
    • If no valid equity data exists (e.g., simulation failed early), return empty results and stop.
  5. Calculate Performance Metrics: Compute various statistics based on the equity curve and trades log:
    • Total Return, Annualized Return
    • Maximum Drawdown (value and percentage)
    • Sharpe Ratio (typically calculated using daily equity returns)
    • Trade Statistics: Win Rate, Average PnL (absolute and percentage), Profit Factor, Number of Trades, etc.
  6. Create Summary Table: Organize the calculated performance metrics into a structured DataFrame or summary object.

7. Output Generation

  1. Add Position Info to Data: Add a column to the original input dataframe indicating the position_type held on each day during the simulation.
  2. Generate Equity Curve Plot: Create a plot (e.g., using ggplot2) showing the portfolio equity over time.
  3. Prepare Data for Detailed Plot: Process data for a multi-panel plot (e.g., pivot longer, add shading for positions, mark trade entry/exit points).
  4. Generate Detailed Plot: Create the multi-panel plot showing prices, ratio, indicators (Z-score, MACD), and trading activity over time.
  5. Return Results: Package all outputs into a list or object containing:
    • Performance Summary table/DF
    • Equity Curve DataFrame
    • Trades Log DataFrame
    • Equity Curve Plot object
    • Detailed Strategy Plot object
    • Original data augmented with strategy position info

-- End of Strategy Logic --