How to Modify the Stock Analysis Logic in daily_stock_analysis: 5 Proven Methods
You modify the stock analysis logic by editing the StockTrendAnalyzer class in src/stock_analyzer.py, updating configuration values in src/config.py, and adjusting scoring thresholds in the _generate_signal method to customize technical indicators, scoring weights, and buy-signal generation.
The ZhuLinsen/daily_stock_analysis repository implements a modular technical analysis engine that transforms OHLCV market data into actionable buy signals using the StockTrendAnalyzer class. To modify the stock analysis logic, you work directly with the calculation methods that handle moving averages, MACD, RSI, and composite scoring. The architecture separates the core algorithm from service orchestration, allowing you to tune the analysis pipeline without affecting notification systems or scheduling components.
Understanding the Core Architecture
Before modifying logic, identify the key components that process market data:
StockTrendAnalyzer(src/stock_analyzer.py): Encapsulates all technical calculations including MA computation, bias analysis, volume assessment, MACD/RSI generation, and signal scoring.TrendAnalysisResult: Dataclass that stores computed metrics and the finalBuySignalenumeration.analyze_stock: Convenience wrapper function that instantiates the analyzer and returns formatted results.analyzer_service.py(src/analyzer_service.py): Service layer that injects configuration and orchestrates the analysis pipeline; typically requires no changes for algorithmic tweaks.Config: Configuration dataclass insrc/config.pythat exposes tunable parameters likebias_threshold.
Method 1: Adjust Moving Average Windows
The moving-average windows (5, 10, 20, 60) are hard-coded in the _calculate_mas method. To add a custom window (e.g., 8-day MA) or change existing periods, modify the method body:
# src/stock_analyzer.py - _calculate_mas method
def _calculate_mas(self, df: pd.DataFrame) -> pd.DataFrame:
df = df.copy()
df['MA5'] = df['close'].rolling(window=5).mean()
df['MA8'] = df['close'].rolling(window=8).mean() # ← new line
df['MA10'] = df['close'].rolling(window=10).mean()
df['MA20'] = df['close'].rolling(window=20).mean()
# ...
return df
To make windows configurable via Config, add fields to src/config.py and reference them:
# src/config.py
ma5_window: int = 5
ma8_window: int = 8 # new configurable window
# src/stock_analyzer.py
cfg = get_config()
df['MA5'] = df['close'].rolling(window=cfg.ma5_window).mean()
df['MA8'] = df['close'].rolling(window=cfg.ma8_window).mean()
Method 2: Change the Bias Threshold
The bias calculation compares price deviation from moving averages. The _generate_signal method reads Config.bias_threshold (default 5%) at line 221. To modify this tolerance globally, set an environment variable:
# .env file or export in shell
BIAS_THRESHOLD=7
For strategy-specific thresholds, extend the configuration:
# src/config.py
bias_threshold_strong: float = 8.0
# src/stock_analyzer.py - inside _generate_signal
effective_threshold = base_threshold
if result.trend_status == TrendStatus.STRONG_BULL:
effective_threshold = cfg.bias_threshold_strong
Method 3: Re-weight Scoring Components
The final signal_score (0-100) aggregates sub-scores across six categories (lines 990-1065). Modify the weight dictionaries in the signal generation logic:
# src/stock_analyzer.py - inside _generate_signal (around line 990)
trend_scores = {
TrendStatus.STRONG_BULL: 30,
TrendStatus.BULL: 26,
TrendStatus.WEAK_BULL: 18, # Default 18 points
TrendStatus.CONSOLIDATION: 12,
TrendStatus.WEAK_BEAR: 8,
TrendStatus.BEAR: 4,
TrendStatus.STRONG_BEAR: 0,
}
# Example: Increase weight for weak bullish trends
trend_scores[TrendStatus.WEAK_BULL] = 22 # Increased from 18
The scoring system also evaluates volume, support-resistance, MACD, and RSI—each with similar weight dictionaries you can adjust.
Method 4: Add a New Technical Indicator
To incorporate ATR (Average True Range) or custom metrics:
- Create a calculation method in
StockTrendAnalyzer - Add the field to
TrendAnalysisResult - Reference the value in
_generate_signal
# src/stock_analyzer.py - new method
def _calculate_atr(self, df: pd.DataFrame, period: int = 14) -> pd.DataFrame:
df = df.copy()
df['tr'] = df[['high', 'low', 'close']].apply(
lambda row: max(
row['high'] - row['low'],
abs(row['high'] - row['close'].shift()),
abs(row['low'] - row['close'].shift())
), axis=1)
df['ATR'] = df['tr'].rolling(window=period).mean()
return df
# Add to TrendAnalysisResult dataclass
@dataclass
class TrendAnalysisResult:
# ... existing fields ...
atr: float = 0.0
Insert the calculation into the main analysis flow before signal generation:
# Inside analyze method
df = self._calculate_atr(df)
result.atr = df['ATR'].iloc[-1]
Method 5: Modify Buy-Signal Thresholds
The mapping from signal_score to BuySignal categories occurs near line 1033. Adjust these cut-offs to make the strategy more aggressive or conservative:
# src/stock_analyzer.py - signal_threshold logic
if score >= 70: # Lowered from 75 for more strong signals
result.buy_signal = BuySignal.STRONG_BUY
elif score >= 55: # Lowered from 60
result.buy_signal = BuySignal.BUY
elif score >= 40:
result.buy_signal = BuySignal.WEAK_BUY
else:
result.buy_signal = BuySignal.NO_SIGNAL
Putting the Changes into Practice
After modifying the bias threshold to 7% and adding the 8-day MA, run a custom analysis:
import pandas as pd
from src.stock_analyzer import analyze_stock
# Load historical OHLCV data
df = pd.read_csv('sample_data/600519.csv', parse_dates=['date'])
# Execute analysis with modified logic
result = analyze_stock(df, code='600519')
# Output summary
print(f"Stock: {result.code}")
print(f"Trend Status: {result.trend_status.value}")
print(f"Signal Score: {result.signal_score}")
print(f"Recommendation: {result.buy_signal.value}")
print("Analysis Reasons:")
for reason in result.signal_reasons:
print(f" • {reason}")
The analyzer reads environment variables at initialization, so ensure BIAS_THRESHOLD=7 is set before importing the module.
Summary
- Primary entry point: Modify
StockTrendAnalyzerinsrc/stock_analyzer.pyto change technical calculation logic. - Configuration layer: Update
src/config.pyto expose new tunable parameters like custom MA windows or bias thresholds. - Scoring weights: Adjust dictionaries in
_generate_signal(lines 990-1065) to reallocate points across trend, volume, MACD, RSI, and support-resistance metrics. - Signal thresholds: Modify the conditional logic near line 1033 to change the score cut-offs that trigger
STRONG_BUY,BUY, orWEAK_BUYsignals. - New indicators: Add calculation methods to
StockTrendAnalyzer, extendTrendAnalysisResultwith new fields, and integrate values into the scoring logic.
Frequently Asked Questions
How do I change the moving average periods without editing source code?
Set the periods via environment variables or extend the Config dataclass in src/config.py to read from the environment. Reference these configuration values inside _calculate_mas instead of hard-coded integers, allowing runtime modification through your .env file or container environment variables.
Where is the buy signal actually generated?
The buy signal is assigned in the _generate_signal method of StockTrendAnalyzer (around line 1033 in src/stock_analyzer.py). This method evaluates the composite signal_score against thresholds to determine whether the output should be STRONG_BUY, BUY, WEAK_BUY, or NO_SIGNAL.
Can I add custom technical indicators like Bollinger Bands?
Yes. Create a new calculation method following the pattern of _calculate_mas or _calculate_atr, add corresponding fields to the TrendAnalysisResult dataclass, and invoke your method in the main analysis flow. Update the scoring logic in _generate_signal to incorporate your new indicator into the final signal calculation.
What files should I avoid modifying when tuning analysis logic?
Avoid editing analyzer_service.py unless you need to change pipeline orchestration or notification behavior. This service file handles high-level coordination and dependency injection, while src/stock_analyzer.py contains the actual algorithmic logic you should modify for technical analysis adjustments.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →