Coverage for source/indicators/volume_profile_indicator_handler.py: 100%
23 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-08-01 20:51 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-08-01 20:51 +0000
1# indicators/volume_profile_indicator_handler.py
3# global imports
4import numpy as np
5import pandas as pd
6from collections import defaultdict
8# local imports
9from source.indicators import IndicatorHandlerBase
11class VolumeProfileIndicatorHandler(IndicatorHandlerBase):
12 """
13 Implements static volume profile indicator. It denotes volume traded at
14 certain price levels. Calculated data can not be directly mapped to input
15 data and should be treated as the separate chart.
16 """
18 def __init__(self, number_of_steps: int = 40) -> None:
19 """
20 Class constructor.
22 Parameters:
23 number_of_steps (int): Number of bins that price should be put into
24 while creating volume profile.
25 """
27 self.__number_of_steps = number_of_steps
29 def calculate(self, data: pd.DataFrame) -> pd.DataFrame:
30 """
31 Calculates static volume profile indicator values for given data.
33 Parameters:
34 data (pd.DataFrame): Data frame with input data.
36 Returns:
37 (pd.DataFrame): Output data with calculated static volume profile values.
38 """
40 volume_profile = defaultdict(float)
41 data_min = data['low'].min()
42 data_max = data['high'].max()
43 step = (data_max - data_min) / (self.__number_of_steps - 1)
45 for _, row in data.iterrows():
46 equalized_low = row['low'] // step * step
47 equalized_high = row['high'] // step * step
48 price_range = np.linspace(equalized_low, equalized_high, num = int(round((equalized_high - equalized_low) / step + 1, 0)))
49 price_range = np.round(price_range, 6 - int(np.floor(np.log10(data_min))))
50 volume_per_step = row['volume'] / len(price_range)
52 for price in price_range:
53 volume_profile[price] += volume_per_step
55 profile_df = pd.DataFrame(list(volume_profile.items()), columns = ['price', 'volume'])
56 profile_df.sort_values(by = 'price', inplace = True)
58 return profile_df