twopirllc / pandas-ta

Technical Analysis Indicators - Pandas TA is an easy to use Python 3 Pandas Extension with 150+ Indicators
https://twopirllc.github.io/pandas-ta/
MIT License
5.28k stars 1.03k forks source link

Cumulative Volume Delta (CVD) #573

Open casper-hansen opened 2 years ago

casper-hansen commented 2 years ago

Hi, I am wondering if we can support CVD? Or if anyone else has a working CVD?

Reference below for a nice CVD indicator: https://www.tradingview.com/script/NlM312nK-CVD-Cumulative-Volume-Delta-Candles/

casper-hansen commented 2 years ago

I made a version that is workable, but not exactly like the one I linked above. The idea is still the same though - we want to reset the CVD every month aka on a higher stepped timeframe.

For the actual operations, I took the code from here and converted it: https://www.tradingview.com/script/SUrJYDo6-Cumulative-Delta-Volume-With-Alerts-and-Plot-Fills/

Blazing fast, but naming/variables could use some work.

import numpy as np
import pandas as pd

def cvd(full_df):
    full_df.index = full_df['open_time'].apply(lambda x: utils.timestamp_to_datetime(x, as_str=False))
    month_groups = full_df.groupby(pd.Grouper(freq='M'))

    monthly_deltas = []

    for _, group in month_groups:
        df = group.copy()

        df['open_close_max'] = df.high - df[["open", "close"]].max(axis=1)
        df['open_close_min'] = df[["open", "close"]].min(axis=1) - df.low
        df['open_close_abs'] = (df.close - df.open).abs()
        df['is_close_larger'] = df.close >= df.open
        df['is_open_larger'] = df.open > df.close
        df['is_body_cond_met'] = df.is_close_larger | df.is_open_larger

        df.loc[df.is_body_cond_met == False, 'open_close_abs_2x'] = 0
        df.loc[df.is_body_cond_met == True, 'open_close_abs_2x'] = 2*df.open_close_abs

        df['nominator'] = df.open_close_max + df.open_close_min + df.open_close_abs_2x
        df['denom'] = df.open_close_max + df.open_close_min + df.open_close_abs

        df['delta'] = 0
        df.loc[df.denom == 0, 'delta'] = 0.5
        df.loc[df.denom != 0, 'delta'] = df.nominator / df.denom
        df.loc[df.is_close_larger == False, 'delta'] = df.loc[df.is_close_larger == False, 'volume'] * (-df.loc[df.is_close_larger == False, 'delta'])
        df.loc[df.is_close_larger == True, 'delta'] = df.loc[df.is_close_larger == True, 'volume'] * (df.loc[df.is_close_larger == True, 'delta'])

        monthly_deltas.append(pd.Series(np.cumsum(df.delta.values)))

    all_deltas = pd.concat(monthly_deltas).reset_index(drop=True)
    full_df = full_df.reset_index(drop=True)
    full_df['cvd'] = all_deltas

    return full_df
twopirllc commented 2 years ago

Hello @casperbh96,

Thanks for providing a link to the source and some sample Python code. Unfortunately with all the outstanding bug and feature requests, I do not have a time frame for completion. Hopefully someone whom also wants it included is willing to submit a PR to expedite the process. 😎

Kind Regards, KJ

phpmac commented 7 months ago

we need this one