- fixing data-type circular import
- removing HOLD signal from saving to database to reduce data size
This commit is contained in:
Vasily.onl 2025-06-12 18:39:11 +08:00
parent 0d6bfea48a
commit 061b467d43
7 changed files with 112 additions and 110 deletions

View File

@ -201,6 +201,67 @@ class ProcessingStats:
}
class SignalType(str, Enum):
"""
Types of trading signals that strategies can generate.
"""
BUY = "buy"
SELL = "sell"
HOLD = "hold"
ENTRY_LONG = "entry_long"
EXIT_LONG = "exit_long"
ENTRY_SHORT = "entry_short"
EXIT_SHORT = "exit_short"
STOP_LOSS = "stop_loss"
TAKE_PROFIT = "take_profit"
@dataclass
class StrategySignal:
"""
Container for individual strategy signals.
Attributes:
timestamp: Signal timestamp (right-aligned with candle)
symbol: Trading symbol
timeframe: Candle timeframe
signal_type: Type of signal (buy/sell/hold etc.)
price: Price at which signal was generated
confidence: Signal confidence score (0.0 to 1.0)
metadata: Additional signal metadata (e.g., indicator values)
"""
timestamp: datetime
symbol: str
timeframe: str
signal_type: SignalType
price: float
confidence: float = 1.0
metadata: Optional[Dict[str, Any]] = None
@dataclass
class StrategyResult:
"""
Container for strategy calculation results.
Attributes:
timestamp: Candle timestamp (right-aligned)
symbol: Trading symbol
timeframe: Candle timeframe
strategy_name: Name of the strategy that generated this result
signals: List[StrategySignal]
indicators_used: Dictionary of indicator values used in calculation
metadata: Additional calculation metadata
"""
timestamp: datetime
symbol: str
timeframe: str
strategy_name: str
signals: List[StrategySignal]
indicators_used: Dict[str, float]
metadata: Optional[Dict[str, Any]] = None
# Re-export from base_collector for convenience
__all__ = [
'DataType',

View File

@ -8,7 +8,7 @@ from sqlalchemy import desc, and_, func
from sqlalchemy.orm import joinedload
from ..models import StrategySignal, StrategyRun
from strategies.data_types import StrategySignal as StrategySignalDataType, StrategyResult
from data.common.data_types import StrategySignal as StrategySignalDataType, StrategyResult
from .base_repository import BaseRepository, DatabaseOperationError
@ -95,23 +95,25 @@ class StrategyRepository(BaseRepository):
with self.get_session() as session:
for result in strategy_results:
for signal in result.signals:
strategy_signal = StrategySignal(
run_id=run_id,
strategy_name=result.strategy_name,
strategy_config=None, # Could be populated from StrategyRun.config
symbol=signal.symbol,
timeframe=signal.timeframe,
timestamp=signal.timestamp,
signal_type=signal.signal_type.value,
price=Decimal(str(signal.price)),
confidence=Decimal(str(signal.confidence)),
signal_metadata={
'indicators_used': result.indicators_used,
'metadata': signal.metadata or {}
}
)
session.add(strategy_signal)
signals_stored += 1
# Only store BUY or SELL signals, not HOLD
if signal.signal_type.value in ["BUY", "SELL"]:
strategy_signal = StrategySignal(
run_id=run_id,
strategy_name=result.strategy_name,
strategy_config=None, # Could be populated from StrategyRun.config
symbol=signal.symbol,
timeframe=signal.timeframe,
timestamp=signal.timestamp,
signal_type=signal.signal_type.value,
price=Decimal(str(signal.price)),
confidence=Decimal(str(signal.confidence)),
signal_metadata={
'indicators_used': result.indicators_used,
'metadata': signal.metadata or {}
}
)
session.add(strategy_signal)
signals_stored += 1
session.commit()
self.log_info(f"Stored {signals_stored} strategy signals for run {run_id}")

View File

@ -14,7 +14,7 @@ IMPORTANT: Mirrors Indicator Patterns
from .base import BaseStrategy
from .factory import StrategyFactory
from .data_types import StrategySignal, SignalType, StrategyResult
from data.common.data_types import StrategySignal, SignalType, StrategyResult
from .manager import StrategyManager, StrategyConfig, StrategyType, StrategyCategory, get_strategy_manager
from .data_integration import StrategyDataIntegrator, StrategyDataIntegrationConfig, get_strategy_data_integrator
from .validation import StrategySignalValidator, ValidationConfig

View File

@ -20,7 +20,7 @@ from data.common.data_types import OHLCVCandle
from data.common.indicators import TechnicalIndicators
from components.charts.config.indicator_defs import convert_database_candles_to_ohlcv
from .factory import StrategyFactory
from .data_types import StrategyResult
from data.common.data_types import StrategyResult
from utils.logger import get_logger
# Initialize logger

View File

@ -1,72 +0,0 @@
"""
Strategy Data Types and Signal Definitions
This module provides data types for strategy calculations, signals,
and results in a standardized format.
"""
from dataclasses import dataclass
from datetime import datetime
from typing import Dict, Optional, Any, List
from enum import Enum
class SignalType(str, Enum):
"""
Types of trading signals that strategies can generate.
"""
BUY = "buy"
SELL = "sell"
HOLD = "hold"
ENTRY_LONG = "entry_long"
EXIT_LONG = "exit_long"
ENTRY_SHORT = "entry_short"
EXIT_SHORT = "exit_short"
STOP_LOSS = "stop_loss"
TAKE_PROFIT = "take_profit"
@dataclass
class StrategySignal:
"""
Container for individual strategy signals.
Attributes:
timestamp: Signal timestamp (right-aligned with candle)
symbol: Trading symbol
timeframe: Candle timeframe
signal_type: Type of signal (buy/sell/hold etc.)
price: Price at which signal was generated
confidence: Signal confidence score (0.0 to 1.0)
metadata: Additional signal metadata (e.g., indicator values)
"""
timestamp: datetime
symbol: str
timeframe: str
signal_type: SignalType
price: float
confidence: float = 1.0
metadata: Optional[Dict[str, Any]] = None
@dataclass
class StrategyResult:
"""
Container for strategy calculation results.
Attributes:
timestamp: Candle timestamp (right-aligned)
symbol: Trading symbol
timeframe: Candle timeframe
strategy_name: Name of the strategy that generated this result
signals: List of signals generated for this timestamp
indicators_used: Dictionary of indicator values used in calculation
metadata: Additional calculation metadata
"""
timestamp: datetime
symbol: str
timeframe: str
strategy_name: str
signals: List[StrategySignal]
indicators_used: Dict[str, float]
metadata: Optional[Dict[str, Any]] = None

View File

@ -207,25 +207,31 @@ class StrategySignalBroadcaster:
result = signal.strategy_result
context = signal.context
signal_data.append({
'strategy_name': context.strategy_name,
'strategy_config': context.strategy_config,
'symbol': context.symbol,
'timeframe': context.timeframe,
'exchange': context.exchange,
'timestamp': result.timestamp,
'signal_type': result.signal.signal_type.value if result.signal else 'HOLD',
'price': float(result.price) if result.price else None,
'confidence': result.confidence,
'signal_metadata': result.metadata or {},
'generation_time': signal.generation_time
})
# Only store BUY or SELL signals, not HOLD
if result.signal and result.signal.signal_type in [SignalType.BUY, SignalType.SELL]:
signal_data.append({
'strategy_name': context.strategy_name,
'strategy_config': context.strategy_config,
'symbol': context.symbol,
'timeframe': context.timeframe,
'exchange': context.exchange,
'timestamp': result.timestamp,
'signal_type': result.signal.signal_type.value,
'price': float(result.price) if result.price else None,
'confidence': result.confidence,
'signal_metadata': result.metadata or {},
'generation_time': signal.generation_time
})
# Batch insert into database
self.db_ops.strategy.store_signals_batch(signal_data)
if self.logger:
self.logger.debug(f"Stored batch of {len(signals)} real-time signals")
if signal_data: # Only call store_signals_batch if there are signals to store
# Batch insert into database
self.db_ops.strategy.store_signals_batch(signal_data)
if self.logger:
self.logger.debug(f"Stored batch of {len(signal_data)} real-time signals")
else:
if self.logger:
self.logger.debug("No BUY/SELL signals to store in this batch.")
except Exception as e:
if self.logger:

View File

@ -102,6 +102,11 @@
- **Reasoning**: Real-time strategy execution requires different architecture than batch processing - event-driven triggers, background signal processing, throttled chart updates, and integration with existing dashboard refresh cycles.
- **Impact**: Enables live strategy signal generation that integrates seamlessly with the existing chart system. Provides concurrent strategy execution, real-time signal storage, error handling with automatic strategy disabling, and performance monitoring for production use.
### 11. Exclusion of "HOLD" Signals from All Signal Storage
- **Decision**: Modified signal storage mechanisms across both real-time and batch processing to exclude "HOLD" signals, only persisting explicit "BUY" or "SELL" signals in the database.
- **Reasoning**: To significantly reduce data volume and improve storage/query performance across all execution types, as the absence of a BUY/SELL signal implicitly means "HOLD" and can be inferred during analysis or visualization.
- **Impact**: Leads to more efficient database usage and faster data retrieval for all stored signals. Requires careful handling in visualization and backtesting components to correctly interpret gaps as "HOLD" periods.
## Tasks
- [x] 1.0 Core Strategy Foundation Setup