Skip to content

CommonSenseRatio

One number that must win on both fronts — the profit factor (the body) multiplied by the tail ratio (the extremes).

Quick reference

FieldValue
FamilyRisk / Performance
Input typef64 (per-period returns)
Output typef64
Output range>= 0, unbounded (> 1 sound, < 1 flawed)
Default parameters(period = 252) (Python)
Warmup periodperiod
Interpretation> 1 good on body and tails; < 1 one of them is failing.

Formula

ProfitFactor = Σ gains / Σ |losses|              over the window
TailRatio    = P95(returns) / |P5(returns)|      over the window
CSR          = ProfitFactor · TailRatio

The Common Sense Ratio multiplies the ProfitFactor (how much you make per unit lost on the average bar) by the TailRatio (whether the largest gains beat the largest losses). The product only sits comfortably above 1.0 when a strategy wins on both: a healthy profit factor can still hide catastrophic left-tail risk, and a fat right tail means nothing if the body bleeds. A window with no losses or no left tail reports 0.0 rather than dividing by zero. Source: crates/wickra-core/src/indicators/common_sense_ratio.rs.

Parameters

NameTypeDefaultValid rangeSourceDescription
periodusize252 (Python)>= 2common_sense_ratio.rs:60Window of returns. < 2 errors with Error::InvalidPeriod.

The period getter returns the window.

Inputs / Outputs

From crates/wickra-core/src/indicators/common_sense_ratio.rs:

rust
use wickra::{Indicator, CommonSenseRatio};
// CommonSenseRatio: Input = f64, Output = f64
const _: fn(&mut CommonSenseRatio, f64) -> Option<f64> =
    <CommonSenseRatio as Indicator>::update;

An f64 return in, an Option<f64> out. Python update(ret) / batch(returns) (NaN warmup); Node update(ret) / batch(returns[]) (null warmup).

Warmup

warmup_period() == period. The first value lands once period returns are seen (reference_value exercises the emission at index period − 1).

Edge cases

  • Reference value. [-0.04, -0.02, 0, 0.02, 0.04] → profit factor 1.0 × tail ratio 1.0 = 1.0 (reference_value pins this).
  • No losses. A loss-free window reports 0.0 (no_losses_is_zero pins this).
  • Flat window. An all-zero window trips the losses guard and reports 0.0 (flat_window_is_zero pins this).
  • Non-finite input. A NaN/∞ return is skipped (ignores_non_finite_input).
  • Reset. csr.reset() clears the window (reset_clears_state pins this).

Examples

Rust

rust
use wickra::{BatchExt, Indicator, CommonSenseRatio};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut csr = CommonSenseRatio::new(5)?;
    let out = csr.batch(&[-0.04, -0.02, 0.0, 0.02, 0.04]);
    println!("{:?}", out[4]); // Some(1.0)
    Ok(())
}

Output:

Some(1.0)

Python

python
import numpy as np
import wickra as ta

csr = ta.CommonSenseRatio(252)
returns = np.random.randn(500) * 0.01
print(csr.batch(returns)[-1])

Node

javascript
const ta = require('wickra');
const csr = new ta.CommonSenseRatio(5);
console.log(csr.batch([-0.04, -0.02, 0.0, 0.02, 0.04]).at(-1)); // 1

Streaming

rust
use wickra::{Indicator, CommonSenseRatio};

let mut csr = CommonSenseRatio::new(252).unwrap();
let daily_returns: Vec<f64> = Vec::new(); // your live stream
for r in daily_returns {
    if let Some(ratio) = csr.update(r) {
        // ratio > 1 -> sound on both body and tails
    }
}

Streaming update and batch are equivalent tick-for-tick (batch_equals_streaming pins this).

Interpretation

  1. Hidden-risk detector. A strategy with a strong profit factor but a CSR below 1.0 is being dragged down by its tails — the average bar lies about the risk.
  2. One-number screen. Robert Carver popularised the CSR as a quick robustness check: anything below 1.0 is fragile regardless of headline returns.
  3. Decompose on a fail. When the CSR is poor, read its two factors separately to learn whether the body (ProfitFactor) or the tails (TailRatio) is to blame.

Common pitfalls

  • Window length. Tail percentiles need many observations — use a year of daily data, not a handful of bars.
  • Zero anomaly. No losses or no left tail reports 0.0 (undefined), not infinity.
  • Multiplicative, not additive. A near-zero factor collapses the whole ratio — that is by design.

References

Schwager, J. D., and popularised by Carver, R. (2015), Systematic Trading — the Common Sense Ratio.

See also