tradai-strategy Design Document¶
Overview¶
tradai-strategy provides the strategy framework for the TradAI platform. It extends Freqtrade's IStrategy with TradAI-specific features: standardized metadata, type-safe enums, validation, and MLflow/Docker integration.
Design Philosophy: Extend, don't wrap. TradAIStrategy IS an IStrategy - it works directly with Freqtrade without adapters.
Architecture Decisions¶
What We Provide¶
- TradAIStrategy (
base.py) - Base class extending IStrategy - Adds
get_metadata()abstract method (REQUIRED) - Adds
validate_configuration()hook (optional) - Includes StrategyDebugMixin for development
-
Full Freqtrade compatibility (all IStrategy hooks work)
-
StrategyMetadata (
metadata.py) - Pydantic model for strategy info - Required: name, version, description, timeframe, category
- Optional: can_short, tags, author, status, parameters
- Live trading fields: trading_modes, exchange, pairs, stake_currency
-
Methods:
to_mlflow_tags(),to_docker_labels() -
Type-Safe Enums (
enums.py) SignalDirection- LONG, SHORTStrategyStatus- ACTIVE, DEPRECATED, TESTINGStrategyCategory- TREND_FOLLOWING, MEAN_REVERSION, BREAKOUT, MOMENTUM, ARBITRAGEBacktestStatus- PENDING, RUNNING, COMPLETED, FAILEDValidationLevel- BASIC, STANDARD, STRICT-
PredictionSource- CSV, MLFLOW -
StrategyValidator (
validation.py) - Server-side validation - Validates strategy class structure
- Validates metadata completeness
-
Validates Freqtrade method signatures
-
Filters (
filters.py) - Signal filtering utilities apply_filters()- Apply multiple filters to signals-
apply_volatility_filter()- Filter by ATR/volatility -
FreqAI Integration (
freqai/) config_builder.py- FreqAI config constructionprediction_model.py- Prediction loading utilitiestraining_model.py- Training utilities-
utils.py- FreqAI helper functions -
Debug Utilities (
debug.py) StrategyDebugMixin- Debug methods for developmentcheck_nan_indicators()- Detect NaN in indicators-
print_indicator_summary()- Print latest candle values -
Quality Checks
sanity/- Runtime sanity checkspreflight/- Pre-execution validationlinting.py- Static analysis rules
What We Don't Provide¶
- Strategy implementations - Live in separate
tradai-strategiesrepo - Backtesting engine - Use Freqtrade directly
- Data fetching - Use
tradai-datalibrary - Common utilities - Use
tradai-commonlibrary
Module Organization¶
tradai/strategy/
├── __init__.py # Public API exports
├── base.py # TradAIStrategy base class
├── metadata.py # StrategyMetadata Pydantic model
├── enums.py # Type-safe enums
├── validation.py # StrategyValidator
├── exceptions.py # StrategyError hierarchy
├── filters.py # Signal filtering utilities
├── dataframe_validators.py # DataFrame validation
├── debug.py # StrategyDebugMixin
├── linting.py # Static analysis rules
├── freqai/ # FreqAI integration
│ ├── __init__.py
│ ├── config_builder.py # FreqAI config construction
│ ├── prediction_model.py # Prediction loading
│ ├── training_model.py # Training utilities
│ └── utils.py # Helper functions
├── sanity/ # Runtime sanity checks
│ ├── __init__.py
│ ├── service.py # Sanity check service
│ └── entities.py # Sanity check entities
└── preflight/ # Pre-execution validation
├── __init__.py
└── entities.py # Preflight entities
Usage Patterns¶
Creating a Strategy¶
from tradai.strategy import TradAIStrategy, StrategyMetadata
from tradai.strategy.enums import StrategyCategory
import talib
class MyStrategy(TradAIStrategy):
"""Example trading strategy."""
timeframe = '1h'
can_short = True
stoploss = -0.08
def get_metadata(self) -> StrategyMetadata:
return StrategyMetadata(
name="MyStrategy",
version="1.0.0",
description="RSI mean reversion",
timeframe=self.timeframe,
can_short=self.can_short,
category=StrategyCategory.MEAN_REVERSION,
tags=["rsi", "mean-reversion"],
)
def populate_indicators(self, dataframe, metadata):
dataframe['rsi'] = talib.RSI(dataframe['close'])
return dataframe
def populate_entry_trend(self, dataframe, metadata):
dataframe.loc[dataframe['rsi'] < 30, 'enter_long'] = 1
return dataframe
def populate_exit_trend(self, dataframe, metadata):
dataframe.loc[dataframe['rsi'] > 70, 'exit_long'] = 1
return dataframe
Live Trading Strategy¶
def get_metadata(self) -> StrategyMetadata:
return StrategyMetadata(
name="LiveMomentumBot",
version="2.1.0",
description="Production momentum strategy",
timeframe="4h",
category=StrategyCategory.MOMENTUM,
# Live trading fields (LM001)
trading_modes=["backtest", "dry-run", "live"],
exchange="binance",
pairs=["BTC/USDT:USDT", "ETH/USDT:USDT"],
stake_currency="USDT",
status=StrategyStatus.ACTIVE,
)
With FreqAI¶
from tradai.strategy.freqai import FreqAIConfigBuilder
class MLStrategy(TradAIStrategy):
"""FreqAI-enabled strategy."""
def get_metadata(self) -> StrategyMetadata:
return StrategyMetadata(
name="MLStrategy",
version="1.0.0",
description="ML-based predictions",
timeframe="1h",
category=StrategyCategory.TREND_FOLLOWING,
tags=["freqai", "ml", "gradient-boosting"],
)
@property
def freqai_config(self) -> dict:
return FreqAIConfigBuilder(
model_name="LightGBMClassifier",
label_period_candles=24,
feature_parameters={
"include_corr_pairlist": ["BTC/USDT:USDT"],
"indicator_periods_candles": [10, 20, 50],
},
).build()
Validation¶
from tradai.strategy import StrategyValidator
from tradai.strategy.enums import ValidationLevel
validator = StrategyValidator(level=ValidationLevel.STANDARD)
result = validator.validate(MyStrategy)
if not result.is_valid:
for error in result.errors:
print(f"Error: {error}")
Relationship to tradai-strategies¶
tradai-strategy (this library) provides the framework: - TradAIStrategy base class - Metadata schema - Validation utilities
tradai-strategies (separate private repo) contains implementations: - Production strategies (PascalStrategy, RadStrategy, etc.) - Example strategies for learning - Strategy-specific tests
tradai-uv/libs/tradai-strategy/ # Framework (public in workspace)
└── src/tradai/strategy/
tradai-strategies/ # Implementations (private repo)
├── strategies/ # Production strategies
│ ├── pascal-strategy/
│ ├── rad-strategy/
│ └── stochastic-strategy/
└── examples/ # Learning examples
├── minimal_strategy/
└── momentum_strategy/
Design Patterns Applied¶
1. Extension Pattern (not Adapter)¶
# TradAIStrategy IS an IStrategy
class TradAIStrategy(IStrategy, StrategyDebugMixin):
# All IStrategy methods work directly
# Additional TradAI features added on top
2. Mixin Pattern (Composition)¶
class StrategyDebugMixin:
"""Debug utilities mixed into TradAIStrategy."""
def check_nan_indicators(self, df, pair): ...
def print_indicator_summary(self, df, pair): ...
class TradAIStrategy(IStrategy, StrategyDebugMixin):
# Gets debug methods without inheritance hierarchy
3. Frozen Entities (Immutability)¶
class StrategyMetadata(BaseModel):
model_config = ConfigDict(frozen=True)
# All fields immutable after creation
4. Type-Safe Enums¶
class StrategyCategory(str, Enum):
"""str inheritance for JSON serialization."""
TREND_FOLLOWING = "trend-following"
MEAN_REVERSION = "mean-reversion"
Dependencies¶
Core: - freqtrade>=2024.1 (strategy framework) - pydantic>=2.0.0 (metadata validation) - pandas>=2.0.0 (dataframe operations)
Optional: - ta-lib (technical indicators) - pandas-ta (additional indicators)
Testing Strategy¶
- Unit Tests (
tests/unit/) - Test metadata validation
- Test enum serialization
-
Test validator logic
-
Integration Tests (
tests/integration/) - Test strategy loading with Freqtrade
-
Test FreqAI integration
-
Example Tests (
tests/examples/) - Verify example strategies work
- Validate with sample data
Test structure:
tests/
├── unit/
│ ├── test_metadata.py
│ ├── test_enums.py
│ ├── test_validation.py
│ ├── sanity/
│ │ └── test_service.py
│ └── preflight/
│ └── test_entities.py
├── freqai/
│ ├── test_config_builder.py
│ ├── test_prediction_model.py
│ └── test_training_model.py
├── test_base.py
├── test_filters.py
├── test_debug.py
└── test_linting.py
Code Quality Standards¶
- Type Hints: 100% coverage (strict mypy)
- Docstrings: Google style for all public APIs
- Test Coverage: 85%+ target
- Absolute Imports: Enforced via Ruff
- Frozen Entities: All Pydantic models use frozen=True
Success Criteria¶
- [ ] All strategies extend TradAIStrategy
- [ ] All strategies implement get_metadata()
- [ ] 85%+ test coverage
- [ ] 100% type hint coverage
- [ ] Server-side validation works
- [ ] MLflow tags generate correctly
- [ ] Docker labels generate correctly
- [ ] FreqAI integration works