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

1# indicators/volume_profile_indicator_handler.py 

2 

3# global imports 

4import numpy as np 

5import pandas as pd 

6from collections import defaultdict 

7 

8# local imports 

9from source.indicators import IndicatorHandlerBase 

10 

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 """ 

17 

18 def __init__(self, number_of_steps: int = 40) -> None: 

19 """ 

20 Class constructor. 

21 

22 Parameters: 

23 number_of_steps (int): Number of bins that price should be put into 

24 while creating volume profile. 

25 """ 

26 

27 self.__number_of_steps = number_of_steps 

28 

29 def calculate(self, data: pd.DataFrame) -> pd.DataFrame: 

30 """ 

31 Calculates static volume profile indicator values for given data. 

32 

33 Parameters: 

34 data (pd.DataFrame): Data frame with input data. 

35 

36 Returns: 

37 (pd.DataFrame): Output data with calculated static volume profile values. 

38 """ 

39 

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) 

44 

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) 

51 

52 for price in price_range: 

53 volume_profile[price] += volume_per_step 

54 

55 profile_df = pd.DataFrame(list(volume_profile.items()), columns = ['price', 'volume']) 

56 profile_df.sort_values(by = 'price', inplace = True) 

57 

58 return profile_df