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=trueandfreqai_model_nameis missing: error - If
freqai_enabled=true,freqai_model_nameis set,REQUIRE_MLFLOW_MODEL=true, andMLFLOW_TRACKING_URIis configured: queries MLflow registry for model existence - MLflow check uses lazy-imported
mlflow.tracking.MlflowClientto reduce cold start
Step 5: Validate Date Range (if provided)¶
- Both
start_dateandend_datemust be 8 characters (YYYYMMDD format) start_datemust be beforeend_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_versionin 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.
Related¶
- backtest-consumer - Consumes validated requests
- compare-models - Uses validated configs