Skip to Content
Kani Private Alpha Test is released 🎉
Algorithm SpecificationPrice Formula

Price Formula — Price Window Analytics

This page documents how Kani computes price window metrics from a set of sampled prices within a time range (a “window”).
These metrics are used for trend detection, dump/pump detection, and risk signals.


1) Definitions

A price window is an ordered list of price samples:

  • P = [p0, p1, ..., pN] (prices)
  • T = [t0, t1, ..., tN] (timestamps, aligned with prices)

Where:

  • N = sampleCount - 1
  • p0 is the first price in the window
  • pN is the last price in the window

Prices must be sorted by timestamp ascending so that “first” and “last” are meaningful.

Example

For a 5-minute window with 1-minute sampling:

T = [1000, 2000, 3000, 4000, 5000] (milliseconds) P = [1.50, 1.52, 1.51, 1.53, 1.55] (prices)

Here, N = 4, p0 = 1.50, and pN = 1.55.


2) Core Output

Kani returns a set of metrics:

  • TWAP
  • Min/Max/Diff
  • Range %
  • From Low → Last %
  • From High → Last %
  • Max Drawdown %
  • Volatility (returns std dev)
  • Trend metrics (slope, r²)
  • Efficiency Ratio
  • Peak → Now metrics (dump/reversal)
  • Trough → Now metrics (pump/recovery)
  • Window shape classification (Straight / TrendNoisy / Choppy)

3) TWAP (Mean of Samples)

In the current implementation, TWAP is the simple mean of sampled prices:

TWAP=1N+1i=0NpiTWAP = \frac{1}{N+1}\sum_{i=0}^{N} p_i

Explanation: TWAP (Time-Weighted Average Price) represents the average price over the window. In this implementation, it’s calculated as the arithmetic mean of all sampled prices, giving equal weight to each sample regardless of time intervals.

Note: this is not time-weighted by sample intervals. If you need a true time-weighted TWAP, you must weight by Δt\Delta t.

Example

Given prices P = [1.50, 1.52, 1.51, 1.53, 1.55]:

TWAP=1.50+1.52+1.51+1.53+1.555=7.615=1.522TWAP = \frac{1.50 + 1.52 + 1.51 + 1.53 + 1.55}{5} = \frac{7.61}{5} = 1.522

The TWAP is $1.522, representing the average price over the window.


4) Price Extremes

4.1 Min / Max

minPrice=min(P)minPrice = \min(P) maxPrice=max(P)maxPrice = \max(P)

Explanation: These identify the lowest and highest prices within the window. Useful for understanding the price range and potential profit/loss boundaries.

Example

For P = [1.50, 1.52, 1.51, 1.53, 1.55]:

  • minPrice = 1.50 (lowest price)
  • maxPrice = 1.55 (highest price)

4.2 Difference (Range in absolute units)

diffPrice=maxPriceminPricediffPrice = maxPrice - minPrice

Explanation: The absolute price range within the window, measured in the same units as the price (e.g., USD, tokens).

Example

Using the same prices:

  • diffPrice = 1.55 - 1.50 = 0.05

This means the price moved $0.05 within the window.


5) Percent Metrics

5.1 Range Percent (relative to low)

rangePct={0if minPrice=0maxPriceminPriceminPrice×100otherwiserangePct = \begin{cases} 0 & \text{if } minPrice = 0 \\ \frac{maxPrice - minPrice}{minPrice} \times 100 & \text{otherwise} \end{cases}

Explanation: Measures the percentage range from the lowest price. A value of 10% means the highest price is 10% above the lowest price.

Example

For minPrice = 1.50 and maxPrice = 1.55:

rangePct=1.551.501.50×100=0.051.50×100=3.33%rangePct = \frac{1.55 - 1.50}{1.50} \times 100 = \frac{0.05}{1.50} \times 100 = 3.33\%

The price range is 3.33% relative to the low.

5.2 From Low to Last Percent

fromLowToLastPct={0if minPrice=0pNminPriceminPrice×100otherwisefromLowToLastPct = \begin{cases} 0 & \text{if } minPrice = 0 \\ \frac{p_N - minPrice}{minPrice} \times 100 & \text{otherwise} \end{cases}

Explanation: Shows how much the current (last) price has moved from the window’s low. Positive values indicate the price is above the low; useful for detecting recovery from dips.

Example

For minPrice = 1.50 and pN = 1.55:

fromLowToLastPct=1.551.501.50×100=3.33%fromLowToLastPct = \frac{1.55 - 1.50}{1.50} \times 100 = 3.33\%

The current price is 3.33% above the window’s low, indicating a recovery.

5.3 From High to Last Percent (negative when below high)

fromHighToLastPct={0if maxPrice=0pNmaxPricemaxPrice×100otherwisefromHighToLastPct = \begin{cases} 0 & \text{if } maxPrice = 0 \\ \frac{p_N - maxPrice}{maxPrice} \times 100 & \text{otherwise} \end{cases}

Explanation: Shows how much the current price has dropped from the window’s high. Negative values indicate the price is below the peak; useful for detecting dumps.

Example

For maxPrice = 1.55 and pN = 1.52:

fromHighToLastPct=1.521.551.55×100=1.94%fromHighToLastPct = \frac{1.52 - 1.55}{1.55} \times 100 = -1.94\%

The current price is 1.94% below the window’s high, indicating a pullback.


6) Max Drawdown Percent

Max drawdown is the worst peak-to-trough drop inside the window. It measures the maximum percentage decline from a peak to a subsequent low.

Let:

peaki=max(p0,p1,...,pi)peak_i = \max(p_0, p_1, ..., p_i)

Explanation: peak_i is the highest price seen up to index i. This tracks the running maximum as we scan through the window.

Then drawdown at point i:

ddi={0if peaki=0peakipipeakiotherwisedd_i = \begin{cases} 0 & \text{if } peak_i = 0 \\ \frac{peak_i - p_i}{peak_i} & \text{otherwise} \end{cases}

Explanation: At each point, we calculate how far the current price has dropped from the peak seen so far. This is expressed as a fraction (0 to 1).

Max drawdown:

drawdownPct=(maxiddi)×100drawdownPct = \left(\max_i dd_i\right) \times 100

Explanation: We find the maximum drawdown across all points and convert it to a percentage.

Example

Consider prices P = [1.50, 1.55, 1.52, 1.48, 1.53]:

  • At index 0: peak_0 = 1.50, dd_0 = 0 (no drawdown yet)
  • At index 1: peak_1 = 1.55, dd_1 = 0 (new peak)
  • At index 2: peak_2 = 1.55, dd_2 = (1.55 - 1.52) / 1.55 = 0.0194 (1.94% drop)
  • At index 3: peak_3 = 1.55, dd_3 = (1.55 - 1.48) / 1.55 = 0.0452 (4.52% drop)
  • At index 4: peak_4 = 1.55, dd_4 = (1.55 - 1.53) / 1.55 = 0.0129 (1.29% drop)

Max drawdown: drawdownPct = 4.52% (the worst drop from peak 1.55 to 1.48)

Interpretation:

  • Higher drawdownPct = the window experienced a deeper drop from a prior high.
  • A drawdown of 10% means the price dropped 10% from its peak within the window.

7) Volatility (Standard Deviation of Returns)

Kani computes simple returns between consecutive samples:

ri={0if pi1=0pipi1pi1otherwisefor i=1..Nr_i = \begin{cases} 0 & \text{if } p_{i-1} = 0 \\ \frac{p_i - p_{i-1}}{p_{i-1}} & \text{otherwise} \end{cases} \quad \text{for } i=1..N

Explanation: Returns measure the percentage change between consecutive prices. A return of 0.02 (2%) means the price increased by 2% from the previous sample.

Then volatility is the standard deviation:

volatility=std(r1,r2,...,rN)volatility = std(r_1, r_2, ..., r_N)

Explanation: Volatility measures how much the returns vary. Higher volatility means more erratic price movements. It’s calculated as the standard deviation of all returns in the window.

A 1-second sampled window and a 1-minute sampled window will produce different volatility magnitudes.

Example

Given prices P = [1.50, 1.52, 1.51, 1.53, 1.55]:

  1. Calculate returns:

    • r1=(1.521.50)/1.50=0.0133r_1 = (1.52 - 1.50) / 1.50 = 0.0133 (1.33%)
    • r2=(1.511.52)/1.52=0.0066r_2 = (1.51 - 1.52) / 1.52 = -0.0066 (-0.66%)
    • r3=(1.531.51)/1.51=0.0132r_3 = (1.53 - 1.51) / 1.51 = 0.0132 (1.32%)
    • r4=(1.551.53)/1.53=0.0131r_4 = (1.55 - 1.53) / 1.53 = 0.0131 (1.31%)
  2. Returns: [0.0133, -0.0066, 0.0132, 0.0131]

  3. Mean return: rˉ=0.00825\bar{r} = 0.00825

  4. Standard deviation (volatility): σ0.0089\sigma \approx 0.0089 (0.89%)

This indicates relatively low volatility with consistent small movements.


8) Trend (Linear Regression)

Kani runs linear regression on points:

(i,pi)for i=0..N(i, p_i) \quad \text{for } i = 0..N

Explanation: Linear regression fits a straight line through the price points, where i is the index (time position) and p_i is the price. This helps identify the overall direction and strength of the trend.

Regression output:

  • slope (price change per bar/index)
  • (goodness-of-fit)

Explanation:

  • Slope: The rate of price change per index unit. Positive slope means upward trend, negative means downward.
  • r² (R-squared): Measures how well the line fits the data. Values range from 0 to 1, where 1 means perfect linear fit.

Example

For prices P = [1.50, 1.52, 1.54, 1.56, 1.58] (strong uptrend):

  • Regression line: p=0.02i+1.50p = 0.02i + 1.50
  • slope = 0.02 (price increases by 0.02 per index)
  • r² ≈ 1.0 (perfect linear fit, very clean trend)

For prices P = [1.50, 1.48, 1.52, 1.49, 1.51] (choppy/no trend):

  • slope ≈ 0.002 (slight upward bias)
  • r² ≈ 0.1 (poor fit, lots of noise)

Interpretation:

  • slope > 0 → uptrend
  • slope < 0 → downtrend
  • r² → 1 → price follows a straighter line (less noise)
  • r² → 0 → price is very choppy, no clear trend

9) Efficiency Ratio (0..1)

Efficiency ratio measures “how straight” the path is by comparing the net movement (straight-line distance) to the total movement (sum of all steps).

Net movement:

net=pNp0net = |p_N - p_0|

Explanation: The absolute difference between the first and last price. This is the “as the crow flies” distance.

Total movement:

total=i=1Npipi1total = \sum_{i=1}^{N} |p_i - p_{i-1}|

Explanation: The sum of all absolute price changes between consecutive samples. This is the total “distance traveled” including all zigzags.

Efficiency Ratio:

ER={1if total=0nettotalotherwiseER = \begin{cases} 1 & \text{if } total = 0 \\ \frac{net}{total} & \text{otherwise} \end{cases}

Explanation: ER is the ratio of net to total movement. A value of 1 means the price moved in a perfectly straight line. Lower values indicate more choppy/zigzag movement.

Example

Clean uptrend: P = [1.50, 1.52, 1.54, 1.56, 1.58]

  • net = |1.58 - 1.50| = 0.08
  • total = 0.02 + 0.02 + 0.02 + 0.02 = 0.08
  • ER = 0.08 / 0.08 = 1.0 (perfect efficiency)

Choppy movement: P = [1.50, 1.52, 1.50, 1.52, 1.50]

  • net = |1.50 - 1.50| = 0.00
  • total = 0.02 + 0.02 + 0.02 + 0.02 = 0.08
  • ER = 0.00 / 0.08 = 0.0 (zero efficiency, lots of back-and-forth)

Interpretation:

  • ER ≈ 1: clean trend (price moved efficiently in one direction)
  • ER ≈ 0: choppy / zigzag (price moved a lot but ended up near where it started)
  • ER ≈ 0.5: moderate efficiency (some trend, some noise)

10) Dump Detection Metrics (Peak → Now)

These metrics detect and quantify price dumps (sudden drops) from the window’s peak.

Let:

  • peakPrice=max(P)peakPrice = \max(P) - The highest price in the window
  • peakIndex=argmax(P)peakIndex = argmax(P) - The index where the peak occurred
  • lastPrice=pNlastPrice = p_N - The current (last) price

Drop from peak:

dropFromPeakPct={0if peakPrice=0lastPricepeakPricepeakPrice×100otherwisedropFromPeakPct = \begin{cases} 0 & \text{if } peakPrice = 0 \\ \frac{lastPrice - peakPrice}{peakPrice} \times 100 & \text{otherwise} \end{cases}

Explanation: The percentage drop from the peak to the current price. Negative values indicate a drop.

Bars since peak:

barsSincePeak=NpeakIndexbarsSincePeak = N - peakIndex

Explanation: How many samples have passed since the peak occurred. Lower values mean the dump happened more recently.

Time since peak (minutes):

dtMin=tNtpeakIndex60000dtMin = \frac{t_N - t_{peakIndex}}{60000}

Explanation: The time elapsed since the peak, in minutes. Useful for understanding dump velocity.

Slope per bar:

slopeFromPeakPctPerBar={0if barsSincePeak=0dropFromPeakPctbarsSincePeakotherwiseslopeFromPeakPctPerBar = \begin{cases} 0 & \text{if } barsSincePeak = 0 \\ \frac{dropFromPeakPct}{barsSincePeak} & \text{otherwise} \end{cases}

Explanation: The average percentage drop per bar since the peak. Higher magnitude (more negative) indicates faster dumping.

Velocity per minute:

velFromPeakPctPerMin={0if dtMin=0dropFromPeakPctdtMinotherwisevelFromPeakPctPerMin = \begin{cases} 0 & \text{if } dtMin = 0 \\ \frac{dropFromPeakPct}{dtMin} & \text{otherwise} \end{cases}

Explanation: The rate of price drop in percentage per minute. This is the most direct measure of dump speed.

Example

Given prices P = [1.50, 1.55, 1.52, 1.48, 1.45] and timestamps T = [0, 60000, 120000, 180000, 240000] (1-minute intervals):

  • peakPrice = 1.55 (at index 1)
  • peakIndex = 1
  • lastPrice = 1.45
  • dropFromPeakPct = (1.45 - 1.55) / 1.55 × 100 = -6.45% (6.45% drop)
  • barsSincePeak = 4 - 1 = 3 (3 bars since peak)
  • dtMin = (240000 - 60000) / 60000 = 3 minutes
  • slopeFromPeakPctPerBar = -6.45% / 3 = -2.15% per bar
  • velFromPeakPctPerMin = -6.45% / 3 = -2.15% per minute

Interpretation:

  • Large negative dropFromPeakPct + negative high magnitude velocity → fast dump.
  • Small barsSincePeak → dump happened recently.
  • In this example: 6.45% drop over 3 minutes = 2.15% per minute (moderate dump speed)

11) Pump / Recovery Metrics (Trough → Now)

These metrics detect and quantify price pumps (sudden rises) or recoveries from the window’s lowest point.

Let:

  • troughPrice=min(P)troughPrice = \min(P) - The lowest price in the window
  • troughIndex=argmin(P)troughIndex = argmin(P) - The index where the trough occurred

Rise from trough:

riseFromTroughPct={0if troughPrice=0lastPricetroughPricetroughPrice×100otherwiseriseFromTroughPct = \begin{cases} 0 & \text{if } troughPrice = 0 \\ \frac{lastPrice - troughPrice}{troughPrice} \times 100 & \text{otherwise} \end{cases}

Explanation: The percentage rise from the trough to the current price. Positive values indicate recovery/pump.

Bars/time since trough computed similarly:

  • barsSinceTrough = N - troughIndex - Number of samples since the trough
  • dtMin = (tN - tTrough)/60000 - Time since trough in minutes
  • slopeFromTroughPctPerBar = riseFromTroughPct / barsSinceTrough - Average rise per bar
  • velFromTroughPctPerMin = riseFromTroughPct / dtMin - Rate of rise per minute

Explanation: These metrics mirror the dump detection metrics but track upward movements instead.

Example

Given prices P = [1.50, 1.48, 1.45, 1.52, 1.55] and timestamps T = [0, 60000, 120000, 180000, 240000]:

  • troughPrice = 1.45 (at index 2)
  • troughIndex = 2
  • lastPrice = 1.55
  • riseFromTroughPct = (1.55 - 1.45) / 1.45 × 100 = 6.90% (6.90% rise)
  • barsSinceTrough = 4 - 2 = 2 (2 bars since trough)
  • dtMin = (240000 - 120000) / 60000 = 2 minutes
  • slopeFromTroughPctPerBar = 6.90% / 2 = 3.45% per bar
  • velFromTroughPctPerMin = 6.90% / 2 = 3.45% per minute

Interpretation:

  • High positive rise + high velocity → fast recovery / pump.
  • In this example: 6.90% rise over 2 minutes = 3.45% per minute (strong recovery)

12) Window Shape Classification

Kani labels the window shape using thresholds from configuration to categorize price movement patterns:

  • straightR2, straightEfficiency - Thresholds for “Straight” classification
  • noisyR2, noisyEfficiency - Thresholds for “TrendNoisy” classification

Explanation: This classification helps understand the nature of price movement:

  • Straight: Clean, efficient trend with minimal noise
  • TrendNoisy: Has a trend but with significant noise/volatility
  • Choppy: No clear trend, lots of back-and-forth movement

Logic:

  1. If:

    • r² >= straightR2 and
    • ER >= straightEfficiency

    Straight

  2. Else if:

    • r² >= noisyR2 or
    • ER >= noisyEfficiency

    TrendNoisy

  3. Else: → Choppy

Example

Straight pattern (typical thresholds: straightR2 = 0.8, straightEfficiency = 0.7):

  • Prices: [1.50, 1.52, 1.54, 1.56, 1.58]
  • r² = 0.99, ER = 1.0
  • Classification: Straight (clean uptrend)

TrendNoisy pattern (typical thresholds: noisyR2 = 0.5, noisyEfficiency = 0.4):

  • Prices: [1.50, 1.52, 1.48, 1.54, 1.50, 1.56]
  • r² = 0.6, ER = 0.5
  • Classification: TrendNoisy (upward trend but with volatility)

Choppy pattern:

  • Prices: [1.50, 1.48, 1.52, 1.49, 1.51, 1.50]
  • r² = 0.1, ER = 0.1
  • Classification: Choppy (no clear direction)

13) Data Quality Gate (Large Gaps)

If the input window contains a large missing-data gap, Kani returns null to avoid producing misleading metrics.

Explanation: When there are large time gaps between samples (e.g., missing data for several minutes), the calculated metrics can be distorted. For example:

  • A large gap followed by a price change would create an artificially high volatility spike
  • Peak/trough detection might miss intermediate values
  • Velocity calculations would be incorrect due to missing time periods

This prevents:

  • fake volatility spikes
  • wrong peak/trough detection
  • wrong dump/pump velocity

Example

Normal window (1-minute intervals):

T = [0, 60000, 120000, 180000, 240000] P = [1.50, 1.52, 1.51, 1.53, 1.55]

✅ Valid - all metrics computed

Window with large gap (missing 5 minutes):

T = [0, 60000, 360000, 420000, 480000] // Gap between 60000 and 360000 P = [1.50, 1.52, 1.48, 1.50, 1.52]

❌ Invalid - returns null to prevent misleading metrics


14) Practical Notes

  • The metrics above are window-relative and depend on:
    • Sampling interval: 1-second vs 1-minute sampling produces different volatility values
    • Window length: A 5-minute window vs 1-hour window will show different trends
    • Market volatility regime: High volatility periods require different thresholds than calm periods
  • Thresholds should be tuned with backtesting or live observation.

Example: Choosing Window Parameters

For fast-moving markets (high-frequency trading):

  • Window: 1-5 minutes
  • Sampling: 1-5 seconds
  • Use tighter thresholds for dump/pump detection

For position trading:

  • Window: 1-24 hours
  • Sampling: 1-5 minutes
  • Use wider thresholds, focus on longer-term trends

For risk monitoring:

  • Window: 5-15 minutes
  • Sampling: 10-30 seconds
  • Balance between responsiveness and noise reduction

If you want, I can also add a section “Signal Rules (Dump / Pump)” that converts these metrics into a single score (0–100) with tunable thresholds.

Last updated on