Skip to content

validate-strategy

Validates strategy configuration for Step Functions workflow. Validates the simplified Step Functions payload (not the full strategy config).

Overview

Property Value
Trigger Step Functions / Direct
Runtime Python 3.11
Timeout 30 seconds
Memory 256 MB
Settings class ValidateStrategySettings

What This Lambda Validates

This handler validates the Step Functions payload only, not the full strategy configuration. The detailed config validation (stoploss, stake amounts, trailing stops, etc.) happens in the ECS container when it loads the strategy. This Lambda provides a fast, lightweight pre-check.

Input Schema: StrategyValidationRequest

Step Functions sends a simplified payload:

{
    "strategy_name": "PascalStrategy",      # Required: must be non-empty string
    "timeframe": "1h",                      # Optional: validated if provided
    "symbols": ["BTC/USDT:USDT"],           # Optional: validated if provided
    "start_date": "20240101",               # Optional: YYYYMMDD format
    "end_date": "20240131",                 # Optional: YYYYMMDD format
    "run_id": "uuid-123",                   # Optional: passed through
    "experiment_name": "backtest-pascal",   # Optional: passed through
    "freqai_enabled": false,                # Optional: triggers FreqAI validation
    "freqai_model_name": "pascal-model"     # Required if freqai_enabled=true
}

The schema uses model_config = {"extra": "allow"} to accept extra fields from Step Functions without failing.

Output Schema

Responses use Step Functions compatible format via LambdaResponse.to_step_functions():

Success

{
    "statusCode": 200,
    "body": {
        "success": true,
        "data": {
            "valid": true,
            "strategy_name": "PascalStrategy",
            "errors": [],
            "warnings": []
        },
        "environment": "dev"
    }
}

Validation Failure

{
    "statusCode": 200,
    "body": {
        "success": true,
        "data": {
            "valid": false,
            "strategy_name": "PascalStrategy",
            "errors": [
                "Invalid timeframe '1x'. Valid options: ['1d', '1h', '1m', '1w', '15m', '30m', '4h', '5m']",
                "Invalid quote currency 'EUR' in BTC/EUR. Valid: ['BTC', 'BUSD', 'ETH', 'USD', 'USDT']"
            ],
            "warnings": []
        },
        "environment": "dev"
    }
}

Environment Variables

Variable Required Default Description
MLFLOW_TRACKING_URI No - MLflow server URL
MLFLOW_TRACKING_USERNAME No - MLflow basic auth username
MLFLOW_TRACKING_PASSWORD No - MLflow basic auth password
MODEL_REGISTRY_NAME No tradai-models MLflow registry name
REQUIRE_MLFLOW_MODEL No false Require model existence for FreqAI strategies

Validation Steps

The handler executes these validation steps in order:

Step 1: Parse StrategyValidationRequest

Parses the event into StrategyValidationRequest using Pydantic. On parse failure, returns schema-level errors (e.g., missing strategy_name).

Step 2: Validate Timeframe (if provided)

Valid timeframes: 1m, 5m, 15m, 30m, 1h, 4h, 1d, 1w

Step 3: Validate Symbols (if provided)

For each symbol: - Must contain / separator (e.g., BTC/USDT) - Base currency: 2-10 characters - Quote currency must be one of: USDT, BUSD, USD, BTC, ETH - For futures (BTC/USDT:USDT): settlement currency validated against the same set

Step 4: FreqAI Checks

  • If freqai_enabled=true and freqai_model_name is missing: error
  • If freqai_enabled=true, freqai_model_name is set, REQUIRE_MLFLOW_MODEL=true, and MLFLOW_TRACKING_URI is configured: queries MLflow registry for model existence
  • MLflow check uses lazy-imported mlflow.tracking.MlflowClient to reduce cold start

Step 5: Validate Date Range (if provided)

  • Both start_date and end_date must be 8 characters (YYYYMMDD format)
  • start_date must be before end_date

Note: strategy_version is not resolved here (#750/#783)

strategy_version is execution-inert — it never selects the strategy code or image (task-def selection is version-independent; images run at :latest). It is validated syntactically on BacktestConfig at submit time and carried for lineage only; this Lambda no longer receives it or resolves it against MLflow (the old resolution + resolved_version output were removed). Strategy version pinning is a v4 Release concern (#602/#366).

Validation Flow

flowchart TD
    A[Receive Event] --> B[Parse StrategyValidationRequest]
    B -->|Invalid| C[Return schema errors]
    B -->|Valid| D{Timeframe provided?}
    D -->|Yes| E[Validate against VALID_TIMEFRAMES set]
    D -->|No| F{Symbols provided?}
    E --> F
    F -->|Yes| G[Validate each symbol format and currencies]
    F -->|No| H{FreqAI enabled?}
    G --> H
    H -->|Yes| I{freqai_model_name provided?}
    H -->|No| J{Dates provided?}
    I -->|No| K[Error: model required]
    I -->|Yes| L{REQUIRE_MLFLOW_MODEL and URI set?}
    L -->|Yes| M[Query MLflow registry]
    L -->|No| J
    M -->|Not found| N[Error: model not found]
    M -->|Found| J
    K --> J
    N --> J
    J -->|Yes| O[Validate date range format and order]
    J -->|No| R[Build ValidationResult]
    O --> R
    R --> S[Return via to_step_functions]
    C --> S

Step Functions Integration

{
  "ValidateStrategy": {
    "Type": "Task",
    "Resource": "arn:aws:lambda:...:validate-strategy",
    "Parameters": {
      "strategy_name.$": "$.strategy_name"
    },
    "ResultPath": "$.validation",
    "Next": "CheckValidation"
  },
  "CheckValidation": {
    "Type": "Choice",
    "Choices": [{
      "Variable": "$.validation.body.data.valid",
      "BooleanEquals": true,
      "Next": "LaunchBacktest"
    }],
    "Default": "ValidationFailed"
  }
}

Pydantic Models

StrategyValidationRequest

Lightweight schema for Step Functions input. Uses extra="allow" to pass through unknown fields.

StrategyConfig

Full strategy configuration schema (for detailed validation if the full config is provided). Uses extra="forbid". Includes risk parameters: stoploss, trailing_stop, stake_amount, max_open_trades.

ValidationResult

Frozen Pydantic model with: valid, strategy_name, errors, warnings.