Bull Power vs Bear Power

Parameters: period = 5

Overview

Bull Power vs Bear Power reduces each candle to a single signed pressure value. The raw formula compares the session range against the open, then scales that imbalance by the closing price. Positive readings suggest the bar structure favored bullish expansion from the open, while negative readings suggest bearish control.

The VectorTA implementation then smooths that raw pressure with an EMA-style running mean. That makes the final series less noisy than the per-bar calculation while still reacting quickly to changes in candle structure. The result works well as a short-horizon momentum-pressure gauge rather than a classical oscillator with fixed overbought and oversold zones.

Defaults: Bull Power vs Bear Power uses `period = 5`.

Implementation Examples

Compute the smoothed pressure line from OHLC slices or from a candle container.

use vector_ta::indicators::bull_power_vs_bear_power::{
    bull_power_vs_bear_power,
    BullPowerVsBearPowerInput,
    BullPowerVsBearPowerParams,
};
use vector_ta::utilities::data_loader::{Candles, read_candles_from_csv};

let open = vec![100.0, 101.2, 102.0, 101.6, 103.1];
let high = vec![101.0, 102.4, 102.8, 103.0, 104.3];
let low = vec![99.4, 100.6, 101.2, 100.9, 102.5];
let close = vec![100.8, 101.9, 101.5, 102.7, 103.8];

let output = bull_power_vs_bear_power(&BullPowerVsBearPowerInput::from_slices(
    &open,
    &high,
    &low,
    &close,
    BullPowerVsBearPowerParams { period: Some(5) },
))?;

let candles: Candles = read_candles_from_csv("data/sample.csv")?;
let candle_output = bull_power_vs_bear_power(
    &BullPowerVsBearPowerInput::with_default_candles(&candles)
)?;

println!("Latest pressure: {:?}", output.values.last());
println!("Candle series length: {}", candle_output.values.len());

API Reference

Input Methods
// From candles
BullPowerVsBearPowerInput::from_candles(&Candles, BullPowerVsBearPowerParams)
    -> BullPowerVsBearPowerInput

// From OHLC slices
BullPowerVsBearPowerInput::from_slices(
    &[f64], &[f64], &[f64], &[f64], BullPowerVsBearPowerParams
) -> BullPowerVsBearPowerInput

// From candles with default parameters
BullPowerVsBearPowerInput::with_default_candles(&Candles)
    -> BullPowerVsBearPowerInput
Parameters Structure
pub struct BullPowerVsBearPowerParams {
    pub period: Option<usize>, // default 5
}
Output Structure
pub struct BullPowerVsBearPowerOutput {
    pub values: Vec<f64>,
}
Validation, Warmup & NaNs
  • All four OHLC slices must be present, non-empty, and the same length.
  • A bar is treated as valid only when open, high, low, and close are finite and close is non-zero.
  • period must be greater than zero and no larger than the data length.
  • The indicator needs at least period valid OHLC bars before the smoothed value becomes finite.
  • Warmup lasts until first_valid_index + period - 1.
  • Streaming resets when it encounters an invalid bar.
  • Batch mode rejects unsupported kernels and invalid integer ranges.
Builder, Streaming & Batch APIs
// Builder
BullPowerVsBearPowerBuilder::new()
    .period(usize)
    .kernel(Kernel)
    .apply_slices(&[f64], &[f64], &[f64], &[f64])

BullPowerVsBearPowerBuilder::new()
    .apply(&Candles)

BullPowerVsBearPowerBuilder::new()
    .into_stream()

// Stream
BullPowerVsBearPowerStream::try_new(BullPowerVsBearPowerParams)
BullPowerVsBearPowerStream::update(open, high, low, close) -> Option<f64>
BullPowerVsBearPowerStream::get_warmup_period() -> usize

// Batch
BullPowerVsBearPowerBatchBuilder::new()
    .period_range(start, end, step)
    .period_static(usize)
    .kernel(Kernel)
    .apply_slices(&[f64], &[f64], &[f64], &[f64])
Error Handling
pub enum BullPowerVsBearPowerError {
    EmptyInputData,
    AllValuesNaN,
    InvalidPeriod { period: usize, data_len: usize },
    NotEnoughValidData { needed: usize, valid: usize },
    InconsistentSliceLengths {
        open_len: usize,
        high_len: usize,
        low_len: usize,
        close_len: usize,
    },
    OutputLengthMismatch { expected: usize, got: usize },
    InvalidRange { start: String, end: String, step: String },
    InvalidKernelForBatch(Kernel),
}

Python Bindings

Python exposes an array-returning single-run function, a streaming class, and a batch function. The single-run binding returns one NumPy array of smoothed pressure values. Batch returns a values matrix plus the tested periods and the final rows and cols shape.

import numpy as np
from vector_ta import (
    bull_power_vs_bear_power,
    bull_power_vs_bear_power_batch,
    BullPowerVsBearPowerStream,
)

open_ = np.asarray(open_values, dtype=np.float64)
high = np.asarray(high_values, dtype=np.float64)
low = np.asarray(low_values, dtype=np.float64)
close = np.asarray(close_values, dtype=np.float64)

values = bull_power_vs_bear_power(
    open_,
    high,
    low,
    close,
    period=5,
    kernel="auto",
)

batch = bull_power_vs_bear_power_batch(
    open_,
    high,
    low,
    close,
    period_range=(5, 9, 2),
    kernel="auto",
)

stream = BullPowerVsBearPowerStream(5)
print(stream.update(open_[-1], high[-1], low[-1], close[-1]))

JavaScript/WASM Bindings

The WASM layer exposes one array-returning function for a normal run, a batch wrapper that returns values plus period metadata, and lower-level allocation and in-place APIs for callers that want to manage their own buffers.

import init, {
  bull_power_vs_bear_power_js,
  bull_power_vs_bear_power_batch_js,
} from "/pkg/vector_ta.js";

await init();

const open = new Float64Array(openValues);
const high = new Float64Array(highValues);
const low = new Float64Array(lowValues);
const close = new Float64Array(closeValues);

const values = bull_power_vs_bear_power_js(open, high, low, close, 5);
console.log(values);

const batch = bull_power_vs_bear_power_batch_js(open, high, low, close, {
  period_range: [5, 9, 2],
});

console.log(batch.values, batch.periods, batch.rows, batch.cols);

CUDA Bindings (Rust)

Additional details for the CUDA bindings can be found inside the VectorTA repository.

Performance Analysis

Comparison:
View:
Placeholder data (no recorded benchmarks for this indicator)

Across sizes, Rust CPU runs about 1.14× faster than Tulip C in this benchmark.

Loading chart...

AMD Ryzen 9 9950X (CPU) | NVIDIA RTX 4090 (GPU)

Related Indicators