'"Multi-factor conviction scoring engine combining technical, momentum"
Scanned 9/4/2026
Install to Claude Code
npx -y skills add paulpas/agent-skill-router --skill conviction-scoring --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Conviction Scoring?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/paulpas-conviction-scoring)More formats (shields.io, HTML) on the badges page.
---
name: conviction-scoring
compatibility: opencode
completeness: 95
content-types:
- code
- guidance
- do-dont
- examples
description: '"Multi-factor conviction scoring engine combining technical, momentum"
trend, volatility, and volume signals with configurable weights'
license: MIT
maturity: stable
metadata:
domain: coding
output-format: code
related-skills: null
role: implementation
scope: implementation
triggers: combining, conviction scoring, conviction-scoring, engine, multi-factor
archetypes:
- tactical
- generation
anti_triggers:
- brainstorming
- vague ideation
- code golf
- over-engineering
response_profile:
verbosity: low
directive_strength: high
abstraction_level: operational
version: "1.0.0"
---
# Skill: coding-conviction-scoring
# Multi-factor conviction scoring engine combining technical, momentum, trend, volatility, and volume signals with configurable weights
## Role / Purpose
This skill covers the pattern for turning raw indicator scores into a single, actionable conviction score for trading decisions. The `ConvictionEngine` is initialized with configurable factor weights, validates those weights at construction, and exposes pure functions for scoring individual signals or batches of signal events.
---
## Key Patterns
### 1. Weight Validation at Construction — Fail Fast
All four weights must be non-negative and must sum to 1.0 (within 0.01 tolerance). These checks run in `__init__` before any weights are stored. A `ConvictionEngine` with bad weights cannot be created.
```python
class ConvictionEngine:
def __init__(
self,
minimum_entry: float = 0.7,
minimum_exit: float = 0.5,
momentum_weight: float = 0.3,
trend_weight: float = 0.3,
volatility_weight: float = 0.2,
volume_weight: float = 0.2,
):
"""Initialize conviction engine - fail fast on invalid params."""
# Guard clause - early exit for invalid inputs
if minimum_entry <= 0 or minimum_entry > 1:
raise ValueError("Minimum entry conviction must be in (0, 1]")
if minimum_exit <= 0 or minimum_exit > 1:
raise ValueError("Minimum exit conviction must be in (0, 1]")
if (
momentum_weight < 0
or trend_weight < 0
or volatility_weight < 0
or volume_weight < 0
):
raise ValueError("Factor weights cannot be negative")
total = momentum_weight + trend_weight + volatility_weight + volume_weight
if abs(total - 1.0) > 0.01:
raise ValueError("Factor weights must sum to 1.0")
self.minimum_entry = minimum_entry
self.minimum_exit = minimum_exit
self.momentum_weight = momentum_weight
self.trend_weight = trend_weight
self.volatility_weight = volatility_weight
self.volume_weight = volume_weight
```
---
### 2. `calculate_conviction()` — Pure Function
All five input scores are validated to be in `[0, 1]` before any calculation. The technical score is the weighted average of the four factor scores. The function returns an immutable `ConvictionScore` model.
```python
def calculate_conviction(
self,
technical_score: float,
momentum_score: float,
trend_score: float,
volatility_score: float,
volume_score: float,
) -> ConvictionScore:
"""Calculate conviction score from component scores - pure function."""
# Guard clause - early exit for invalid inputs
for score in [technical_score, momentum_score, trend_score, volatility_score, volume_score]:
if score < 0 or score > 1:
raise ValueError(f"All scores must be in [0, 1], got {score}")
# Weighted average formula for technical score
technical = (
self.momentum_weight * momentum_score
+ self.trend_weight * trend_score
+ self.volatility_weight * volatility_score
+ self.volume_weight * volume_score
)
overall = technical
return ConvictionScore(
overall=overall,
technical=technical,
momentum=momentum_score,
trend=trend_score,
volatility=volatility_score,
volume=volume_score,
)
```
---
### 3. `should_enter()` / `should_exit()` — Threshold Checks
Pure boolean functions. No side effects, no mutations. Callers get a clear decision without knowing the threshold values.
```python
def should_enter(self, conviction_score: ConvictionScore) -> bool:
"""Determine if position should be entered - pure function."""
return conviction_score.overall >= self.minimum_entry
def should_exit(self, conviction_score: ConvictionScore) -> bool:
"""Determine if position should be exited - pure function."""
return conviction_score.overall <= self.minimum_exit
```
---
### 4. Scoring from Signal Events — Batch and Single
`score_signal_event()` scores a single `SignalEvent` using `signal.confidence` as the technical score and extracting factor scores from the signal's metadata. `calculate_conviction_from_signals()` aggregates a list of signals by averaging each factor across all signals.
```python
def score_signal_event(self, signal: SignalEvent) -> ConvictionScore:
"""Score a single signal event - pure function."""
if not signal:
raise ValueError("Signal cannot be None")
metadata = signal.metadata or {}
return self.calculate_conviction(
technical_score=signal.confidence,
momentum_score=metadata.get("momentum_score", 0.5),
trend_score=metadata.get("trend_score", 0.5),
volatility_score=metadata.get("volatility_score", 0.5),
volume_score=metadata.get("volume_score", 0.5),
)
def calculate_conviction_from_signals(
self,
signal_events: list[SignalEvent],
) -> ConvictionScore:
"""Calculate conviction from list of signal events - pure function."""
if not signal_events:
raise ValueError("Signal events list cannot be empty")
momentum_scores = []
trend_scores = []
volatility_scores = []
volume_scores = []
for signal in signal_events:
metadata = signal.metadata or {}
momentum_scores.append(metadata.get("momentum_score", 0.5))
trend_scores.append(metadata.get("trend_score", 0.5))
volatility_scores.append(metadata.get("volatility_score", 0.5))
volume_scores.append(metadata.get("volume_score", 0.5))
import numpy as np
momentum_score = np.mean(momentum_scores)
trend_score = np.mean(trend_scores)
volatility_score = np.mean(volatility_scores)
volume_score = np.mean(volume_scores)
technical_score = np.mean([s.confidence for s in signal_events])
return self.calculate_conviction(
technical_score=technical_score,
momentum_score=momentum_score,
trend_score=trend_score,
volatility_score=volatility_score,
volume_score=volume_score,
)
```
---
### 5. Module-Level Pure Function
A standalone function wraps the engine for callers who have a pre-built engine instance.
```python
def calculate_conviction_score(
technical: float,
momentum: float,
trend: float,
volatility: float,
volume: float,
engine: ConvictionEngine,
) -> ConvictionScore:
"""Calculate conviction score using provided engine - pure function."""
return engine.calculate_conviction(
technical_score=technical,
momentum_score=momentum,
trend_score=trend,
volatility_score=volatility,
volume_score=volume,
)
```
---
## Code Examples
### Engine Setup and Single Signal Scoring
```python
from apex.signals.conviction import ConvictionEngine
from apex.core.models import SignalEvent, SignalType
# Create engine - raises immediately if weights don't sum to 1.0
engine = ConvictionEngine(
minimum_entry=0.7,
minimum_exit=0.5,
momentum_weight=0.3,
trend_weight=0.3,
volatility_weight=0.2,
volume_weight=0.2,
)
# Signal with metadata scores
signal = SignalEvent(
symbol="BTC/USDT",
signal_type=SignalType.LONG,
confidence=0.82,
price=65_000.0,
timeframe="1h",
metadata={
"momentum_score": 0.75,
"trend_score": 0.80,
"volatility_score": 0.60,
"volume_score": 0.70,
},
)
score = engine.score_signal_event(signal)
# Decision gate
if engine.should_enter(score):
print(f"Enter long — conviction: {score.overall:.2f}")
else:
print(f"Skip — conviction too low: {score.overall:.2f}")
```
### Direct Score Calculation
```python
score = engine.calculate_conviction(
technical_score=0.80,
momentum_score=0.75,
trend_score=0.80,
volatility_score=0.60,
volume_score=0.70,
)
# technical = 0.3*0.75 + 0.3*0.80 + 0.2*0.60 + 0.2*0.70
# = 0.225 + 0.24 + 0.12 + 0.14 = 0.725
print(score.overall) # 0.725
print(score.technical) # 0.725
```
### Batch Scoring from Multiple Signals
```python
signals = [signal_1, signal_2, signal_3] # Each with metadata scores
combined_score = engine.calculate_conviction_from_signals(signals)
print(f"Aggregate conviction: {combined_score.overall:.3f}")
```
---
## When to Use Conviction vs Raw Signals
| Use case | Recommendation |
|---|---|
| Single indicator trigger | Raw signal confidence |
| Multi-indicator confluence | Conviction scoring |
| Entry/exit threshold decisions | `should_enter()` / `should_exit()` |
| Comparing signals across strategies | Normalized conviction score |
| Backtesting entry quality | Record conviction at entry |
---
## Philosophy Checklist
- **Early Exit**: Weight validation and score range validation run at the top of their respective methods
- **Parse Don't Validate**: Scores in `[0, 1]` are checked once at `calculate_conviction()`; `ConvictionScore` model then trusts them
- **Atomic Predictability**: All scoring functions are pure — same inputs always produce the same `ConvictionScore`
- **Fail Fast**: Invalid weights halt engine construction; out-of-range scores halt calculation; empty signal list raises
- **Intentional Naming**: `should_enter`, `should_exit`, `score_signal_event`, `calculate_conviction_from_signals` — reads like a decision flow
---
## Constraints
### MUST DO
- Include at least one BAD/GOOD code example pair
- Reference a relevant standard (OWASP, SOLID, DRY, KISS, etc.)
- Use type hints on all function signatures
### MUST NOT DO
- Use magic numbers or hardcoded configuration values
- Bypass error handling for assumed-valid inputs
- Write functions longer than 50 lines without decomposition
## Live References
> Authoritative documentation links for this domain. The model follows markdown links at load time to resolve external references and inline content.
- [Technical Analysis Indicators Reference (Investopedia)](https://www.investopedia.com/terms/t/technical-indicators.asp) — Investopedia's comprehensive reference on technical indicators used in conviction scoring
- [Machine Learning for Financial Forecasting (Goodfellow et al.)](https://www.deeplearningbook.org/) — Goodfellow's Deep Learning textbook with chapters on time series prediction and feature engineering
- [Weighted Scoring Models (Project Management Institute)](https://www.pmi.org/) — PMI standards for multi-factor decision scoring applicable to conviction system design
- [Signal Processing for Trading Systems (Ernest Chan)](https://epchan.blogspot.com/) — Ernest Chan's blog on quantitative trading signals and signal processing techniques
- [Ensemble Learning Methods (scikit-learn)](https://scikit-learn.org/stable/modules/ensemble.html) — scikit-learn's ensemble methods for combining multiple prediction signals
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!