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 final BuySignal enumeration.
  • 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 in src/config.py that exposes tunable parameters like bias_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:

  1. Create a calculation method in StockTrendAnalyzer
  2. Add the field to TrendAnalysisResult
  3. 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 StockTrendAnalyzer in src/stock_analyzer.py to change technical calculation logic.
  • Configuration layer: Update src/config.py to 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, or WEAK_BUY signals.
  • New indicators: Add calculation methods to StockTrendAnalyzer, extend TrendAnalysisResult with 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →