Koding Books

Professional, free coding tutorials

On Balance Volume stock indicator

The on-balance volume (OBV) indicator can be used to make trading decisions by identifying buying and selling pressure trends. It is a technical analysis indicator that measures buying and selling pressure by adding the volume on up days and subtracting the volume on down days.

Here are some ways you can use the OBV indicator:

  1. Trend confirmation: If the OBV is trending upwards along with the price, it can be a confirmation of an uptrend. Similarly, if the OBV is trending downwards along with the price, it can be a confirmation of a downtrend.
  2. Divergence: If the price is trending upwards, but the OBV is trending downwards, it can be a bearish divergence, indicating that the buying pressure is decreasing, and the price may soon reverse. Conversely, if the price is trending downwards, but the OBV is trending upwards, it can be a bullish divergence, indicating that the selling pressure is decreasing, and the price may soon reverse.
  3. Breakouts: If the price breaks out of a range with high volume and the OBV confirms the breakout by trending upwards, it can be a bullish signal. Conversely, if the price breaks down from a range with high volume and the OBV confirms the breakout by trending downwards, it can be a bearish signal.
  4. Support and resistance: If the price is approaching a support or resistance level and the OBV is trending upwards, it can be a bullish signal that the support level will hold. Conversely, if the price is approaching a support or resistance level and the OBV is trending downwards, it can be a bearish signal that the resistance level will hold.

Algorithm

  1. Initialize the on-balance volume (OBV) variable to zero.
  2. Loop through each day’s data, starting from the second day.
  3. If the current day’s closing price is higher than the previous day’s closing price, add the current day’s volume to the OBV.
  4. If the current day’s closing price is lower than the previous day’s closing price, subtract the current day’s volume from the OBV.
  5. If the current day’s closing price is equal to the previous day’s closing price, do not change the OBV.
  6. Repeat steps 3-5 for each day.
  7. The final value of the OBV is the on-balance volume for the given data

C++ implementation

Folder Structure

app/
 obj.cpp
 test_obj.cpp

test_obj.cpp

#include <gtest/gtest.h>
#include <vector>
#include "obv.h"

using namespace std;

TEST(OBVTest, CalculatesOBV) {
    vector<double> prices = {10.0, 12.0, 11.0, 13.0, 12.0};
    vector<double> volumes = {1000, 2000, 1500, 3000, 2500};
    double obv = calculateOBV(prices, volumes);
    EXPECT_EQ(obv, 5000);
}

int main(int argc, char **argv) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

In this test, we create two vectors – one for the closing prices and one for the volumes – and pass them to the calculateOBV function. We then use the EXPECT_EQ macro to check that the calculated OBV value matches the expected value of 5000. Finally, we use the RUN_ALL_TESTS macro to run the test. Note that we include the obv. h header file, which contains the calculateOBV function.

obj.cpp

#include <iostream>
#include <vector>

using namespace std;

double calculateOBV(const vector<double>& prices, const vector<double>& volumes) {
    double obv = 0;
    double prev_price = prices[0];
    for (int i = 1; i < prices.size(); i++) {
        if (prices[i] > prev_price) {
            obv += volumes[i];
        } else if (prices[i] < prev_price) {
            obv -= volumes[i];
        }
        prev_price = prices[i];
    }
    return obv;
}

int main() {
    vector<double> prices = {10.0, 12.0, 11.0, 13.0, 12.0};
    vector<double> volumes = {1000, 2000, 1500, 3000, 2500};
    double obv = calculateOBV(prices, volumes);
    cout << "On-Balance Volume: " << obv << endl;
    return 0;
}

We have two vectors – one for the closing prices and one for the volumes. We pass these vectors to the calculateOBV function, which returns the final OBV value. The function loops through each day’s data and updates the OBV based on the abovementioned rules. Finally, we print the OBV value to the console.

Python Implementation

Folder Structure

app/
 obj.py
 test_obj.py

test_obj.py

import pandas as pd
import pytest
from obv import calculate_obv_dataframe

@pytest.mark.parametrize("data, expected_obv", [
    ({'Date': ['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-05'],
      'Close': [10.0, 12.0, 11.0, 13.0, 12.0],
      'Volume': [1000, 2000, 1500, 3000, 2500]},
     [0, 2000, 500, 3500, 1000]),
    ({'Date': ['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-05'],
      'Close': [5.0, 7.0, 6.0, 8.0, 7.0],
      'Volume': [500, 1000, 750, 1500, 1250]},
     [0, 1000, 250, 1750, 500])
])
def test_calculate_obv_dataframe(data, expected_obv):
    df = pd.DataFrame(data)
    obv = calculate_obv_dataframe(df)
    assert obv == expected_obv

In this test, we use the parametrize decorator to test multiple data sets. Each data set is defined as a dictionary containing the price, volume data, and expected OBV values. We then pass each data set and expected OBV values as arguments to the test function using the @pytest.mark.parametrize decorator.

obj.py

import pandas as pd

def calculate_obv(prices, volumes):
    obv = 0
    prev_price = prices[0]
    for i in range(1, len(prices)):
        if prices[i] > prev_price:
            obv += volumes[i]
        elif prices[i] < prev_price:
            obv -= volumes[i]
        prev_price = prices[i]
    return obv

def calculate_obv_dataframe(df):
    obv = [0]
    prev_price = df['Close'].iloc[0]
    for i in range(1, len(df)):
        if df['Close'].iloc[i] > prev_price:
            obv.append(obv[-1] + df['Volume'].iloc[i])
        elif df['Close'].iloc[i] < prev_price:
            obv.append(obv[-1] - df['Volume'].iloc[i])
        else:
            obv.append(obv[-1])
        prev_price = df['Close'].iloc[i]
    return obv

# Example usage
df = pd.read_csv('data.csv')
obv = calculate_obv_dataframe(df)
df['OBV'] = obv

This implementation uses the pandas library to read in a CSV file containing the price and volume data. The calculate_obv_dataframe function takes a pandas DataFrame as input and returns a list of OBV values. The function uses a for loop to iterate through each row of the DataFrame and updates the OBV based on the rules outlined in the algorithm. The prev_price variable is used to store the previous day’s closing price.

Note that this implementation assumes that the DataFrame has columns named ‘Close’ and ‘Volume’ containing the closing prices and volumes, respectively.

This implementation has a time complexity of O(n), where n is the number of data points, which is the best possible time complexity for this calculation.

The last byte…

On Balance Volume (OBV) is a technical indicator that measures the buying and selling pressure of a security by analyzing its volume. It is based on the idea that volume is the key force behind market movements and that changes in volume can predict price changes. OBV is calculated by adding the volume of a day when the price goes up and subtracting the volume of a day when the price goes down. The result is a cumulative total that shows the net volume flow into or out of a security. OBV can confirm price trends, identify divergences, and anticipate reversals. OBV is often plotted as a line chart along with the price chart for easy comparison

Ali Kayani

https://www.linkedin.com/in/ali-kayani-silvercoder007/

Post navigation

Leave a Comment

Leave a Reply

Your email address will not be published. Required fields are marked *

Rust in Action

Capital Asset Pricing Model (CAPM)

CMAKE – A practical introduction

[ C++ ] Challenge | Variable Sized Arrays