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
    "strategy_version": "latest",           # Optional: version specifier for MLflow resolution
    "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": [],
            "resolved_version": "3"         # Empty string if not resolved
        },
        "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": [],
            "resolved_version": ""
        },
        "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

Step 6: Resolve Strategy Version from MLflow

When strategy_version and MLFLOW_TRACKING_URI are both provided, the handler resolves the version using MLflowAdapter:

Version Specifier Resolution Method
latest adapter.get_model_version(name, version=None) returns latest
production adapter.get_production_version(name) returns Production stage version
staging Searches registered_model.latest_versions for Staging stage
archived Searches registered_model.latest_versions for Archived stage
none Returns None (not a valid stage for resolution)
Numeric (e.g., "3") adapter.get_model_version(name, version="3") validates existence
  • Resolved version is returned as resolved_version in the result (e.g., "3")
  • Empty string if not resolved (Step Functions requires non-null env var values)
  • Version resolution failure is a warning, not an error (strategy may not yet be in registry)

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| P{strategy_version and MLflow configured?}
    O --> P
    P -->|Yes| Q[Resolve version from MLflow]
    P -->|No| R[Build ValidationResult]
    Q --> 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",
      "strategy_version.$": "$.strategy_version",
      "timeframe.$": "$.timeframe",
      "symbols.$": "$.symbols",
      "start_date.$": "$.start_date",
      "end_date.$": "$.end_date",
      "freqai_enabled.$": "$.freqai_enabled"
    },
    "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, resolved_version.