MODELS

Model V0.1

The exact production inputs, formula, gates, components, and edge cases.

#Inputs and window

For every configured symbol, V0.1 reads the latest 20 persisted observations by default. Each contains bid, ask, midpoint, source timestamp, and receipt timestamp. The model uses the equal-weight series across the configured universe and, when configured, the benchmark series.

The score is withheld unless every required series reaches the full window. The oldest required source timestamp must be no more than 90 seconds old at evaluation. Halted quotes, invalid numeric values, and failed API responses never enter the series.

#Exact formula

assetMomentumPct = mean((lastMid - firstMid) / firstMid Γ— 100)
benchmarkMomentumPct = benchmark window return, or 0 for basket models
relativeMovementPct = assetMomentumPct - benchmarkMomentumPct
consistency = aligned consecutive basket steps / 19
spreadQuality = 1 - clamp(averageSpreadBps / 50, 0, 1)

score = round(clamp(50
  + clamp(assetMomentumPct Γ— 5, -15, 15)
  + clamp(relativeMovementPct Γ— 8, -20, 20)
  + (consistency - 0.5) Γ— 20
  + (spreadQuality - 0.5) Γ— 10,
0, 100))

#Stored components

ComponentRange / behaviorSource
momentumContributionClipped to -15…15Universe midpoint return
relativeContributionClipped to -20…20Universe minus benchmark
consistencyContributionApproximately -10…10Direction-aligned steps
qualityContribution-5…5Average bid/ask spread

#Stance thresholds

Scores 0 through 33 classify UNDERWEIGHT. Scores 34 through 66 classify NEUTRAL. Scores 67 through 100 classify OVERWEIGHT. Boundary tests cover 33/34 and 66/67 exactly.

#Edge cases

A non-positive first midpoint produces zero percent change rather than division by zero, but upstream validation normally rejects non-positive midpoints. A flat basket assigns a positive total-direction fallback solely to make consistency deterministic. A missing required or benchmark series prevents output. Spread quality is clipped so an extremely wide spread cannot push the component below its documented bound.

#TypeScript reference

const result = scoreConviction(seriesBySymbol, benchmarkSymbol, {
  requiredObservations: 20,
  requiredSymbols: universe,
  maxSourceAgeSeconds: 90,
  now: Date.now(),
  thresholds: { underweightMax: 33, overweightMin: 67 },
  weights: { momentum: 5, relative: 8, consistency: 20, quality: 10 },
});

#Limitations