stock-pandas


Namestock-pandas JSON
Version 1.2.0 PyPI version JSON
download
home_pagehttps://github.com/kaelzhang/stock-pandas
SummaryThe wrapper of `pandas.DataFrame` with stock statistics and indicators support.
upload_time2023-04-07 01:59:43
maintainer
docs_urlNone
authorKael Zhang
requires_python>=3.6
licenseMIT
keywords pandas pandas-dataframe stock stat indicators macd
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI
coveralls test coverage No coveralls.
            [![](https://travis-ci.org/kaelzhang/stock-pandas.svg?branch=master)](https://travis-ci.org/kaelzhang/stock-pandas)
[![](https://codecov.io/gh/kaelzhang/stock-pandas/branch/master/graph/badge.svg)](https://codecov.io/gh/kaelzhang/stock-pandas)
[![](https://img.shields.io/pypi/v/stock-pandas.svg)](https://pypi.org/project/stock-pandas/)
[![](https://img.shields.io/pypi/l/stock-pandas.svg)](https://github.com/kaelzhang/stock-pandas)


[ma]: #ma-simple-moving-averages
[ema]: #ema-exponential-moving-average
[macd]: #macd-moving-average-convergence-divergence
[boll]: #boll-bollinger-bands
[rsv]: #rsv-raw-stochastic-value
[kdj]: #kdj-a-variety-of-stochastic-oscillator
[kdj]: #kdjc-another-variety-of-stochastic-oscillator
[rsi]: #rsi-relative-strength-index
[bbi]: #bbi-bull-and-bear-index
[llv]: #llv-lowest-of-low-values
[hhv]: #hhv-highest-of-high-values
[column]: #column
[increase]: #increase
[style]: #style
[repeat]: #repeat
[change]: #change
[cumulation]: #cumulation-and-datetimeindex
[datetimeindex]: https://pandas.pydata.org/docs/reference/api/pandas.DatetimeIndex.html


# [stock-pandas](https://github.com/kaelzhang/stock-pandas)

**stock-pandas** inherits and extends `pandas.DataFrame` to support:
- Stock Statistics
- Stock Indicators, including:
  - Trend-following momentum indicators, such as [**MA**][ma], [**EMA**][ema], [**MACD**][macd], [**BBI**][bbi]
  - Dynamic support and resistance indicators, such as [**BOLL**][boll]
  - Over-bought / over-sold indicators, such as [**KDJ**][kdj], [**RSI**][rsi]
  - Other indicators, such as [**LLV**][llv], [**HHV**][hhv]
  - For more indicators, welcome to [request a proposal](https://github.com/kaelzhang/stock-pandas/issues/new?assignees=&labels=feature&template=FEATURE_REQUEST.md&title=), or fork and send me a pull request, or extend stock-pandas yourself. You might read the [Advanced Sections](https://github.com/kaelzhang/stock-pandas#advanced-sections) below.
- To [cumulate][cumulation] kline data based on a given time frame, so that it could easily handle real-time data updates.

`stock-pandas` makes automatical trading much easier. `stock-pandas` requires Python >= **3.6** and Pandas >= **1.0.0**(for now)

With the help of `stock-pandas` and mplfinance, we could easily draw something like:

![](boll.png)

The code example is available at [here](https://github.com/kaelzhang/stock-pandas-examples/blob/master/example/bollinger_bands.ipynb).

## Install

For now, before installing `stock-pandas` in your environment

#### Have `g++` compiler installed

```sh
# With yum, for CentOS, Amazon Linux, etc
yum install gcc-c++

# With apt-get, for Ubuntu
apt-get install g++

# For macOS, install XCode commandline tools
xcode-select --install
```

If you use docker with `Dockerfile` and use python image,

```Dockerfile
FROM python:3.8

...
```

The default `python:3.8` image already contains g++, so we do not install g++ additionally.

#### Install `stock-pandas`

```sh
# Installing `stock-pandas` requires `numpy` to be installed first
pip install numpy

pip install stock-pandas
```

Be careful, you still need to install `numpy` explicitly even if `numpy` and `stock-pandas` both are contained in `requirement.txt`

```txt
numpy
stock-pandas
other-dependencies
...
```

```sh
pip install numpy

pip install -r requirement.txt
```

## Usage

```py
from stock_pandas import StockDataFrame

# or
import stock_pandas as spd
```

We also have some examples with annotations in the [`example`](https://github.com/kaelzhang/stock-pandas/tree/master/example) directory, you could use [JupyterLab](https://jupyter.org/) or Jupyter notebook to play with them.

### StockDataFrame

`StockDataFrame` inherits from `pandas.DataFrame`, so if you are familiar with `pandas.DataFrame`, you are already ready to use `stock-pandas`

```py
import pandas as pd
stock = StockDataFrame(pd.read_csv('stock.csv'))
```

As we know, we could use `[]`, which called **pandas indexing** (a.k.a. `__getitem__` in python) to select out lower-dimensional slices. In addition to indexing with `colname` (column name of the `DataFrame`), we could also do indexing by `directive`s.

```py
stock[directive] # Gets a pandas.Series

stock[[directive0, directive1]] # Gets a StockDataFrame
```

We have an example to show the most basic indexing using `[directive]`

```py
stock = StockDataFrame({
    'open' : ...,
    'high' : ...,
    'low'  : ...,
    'close': [5, 6, 7, 8, 9]
})

stock['ma:2']

# 0    NaN
# 1    5.5
# 2    6.5
# 3    7.5
# 4    8.5
# Name: ma:2,close, dtype: float64
```

Which prints the 2-period simple moving average on column `"close"`.

#### Parameters

- **date_col** `Optional[str] = None` If set, then the column named `date_col` will convert and set as [`DateTimeIndex`](datetimeindex) of the data frame
- **to_datetime_kwargs** `dict = {}` the keyworded arguments to be passed to `pandas.to_datetime()`. It only takes effect if `date_col` is specified.
- **time_frame** `str | TimeFrame | None = None` time frame of the stock. For now, only the following time frames are supported:
    - `'1m'` or `TimeFrame.M1`
    - `'3m'` or `TimeFrame.M3`
    - `'5m'` or `TimeFrame.M5`
    - `'15m'` or `TimeFrame.M15`
    - `'30m'` or `TimeFrame.M30`
    - `'1h'` or `TimeFrame.H1`
    - `'2h'` or `TimeFrame.H2`
    - `'4h'` or `TimeFrame.H4`
    - `'6h'` or `TimeFrame.H6`
    - `'8h'` or `TimeFrame.H8`
    - `'12h'` or `TimeFrame.H12`

### stock.exec(directive: str, create_column: bool=False) -> np.ndarray

Executes the given directive and returns a numpy ndarray according to the directive.

```py
stock['ma:5'] # returns a Series

stock.exec('ma:5', create_column=True) # returns a numpy ndarray
```

```py
# This will only calculate without creating a new column in the dataframe
stock.exec('ma:20')
```

The difference between `stock[directive]` and `stock.exec(directive)` is that
- the former will create a new column for the result of `directive` as a cache for later use, while `stock.exec(directive)` does not unless we pass the parameter `create_column` as `True`
- the former one accepts other pandas indexing targets, while `stock.exec(directive)` only accepts a valid **stock-pandas** directive string
- the former one returns a `pandas.Series` or `StockDataFrame` object while the latter one returns an [`np.ndarray`](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.html)

### stock.alias(alias: str, name: str) -> None

Defines column alias or directive alias

- **alias** `str` the alias name
- **name** `str` the name of an existing column or the directive string

```py
# Some plot library such as `mplfinance` requires a column named capitalized `Open`,
# but it is ok, we could create an alias.
stock.alias('Open', 'open')

stock.alias('buy_point', 'kdj.j < 0')
```

### stock.get_column(key: str) -> pd.Series

Directly gets the column value by `key`, returns a pandas `Series`.

If the given `key` is an alias name, it will return the value of corresponding original column.

If the column is not found, a `KeyError` will be raised.

```py
stock = StockDataFrame({
    'open' : ...,
    'high' : ...,
    'low'  : ...,
    'close': [5, 6, 7, 8, 9]
})

stock.get_column('close')
# 0    5
# 1    6
# 2    7
# 3    8
# 4    9
# Name: close, dtype: float64
```

```py
try:
    stock.get_column('Close')
except KeyError as e:
    print(e)

    # KeyError: column "Close" not found

stock.alias('Close', 'close')

stock.get_column('Close')
# The same as `stock.get_column('close')`
```

### stock.append(other, *args, **kwargs) -> StockDataFrame

Appends rows of `other` to the end of caller, returning a new object.

This method has nearly the same hehavior of [`pandas.DataFrame.append()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.append.html), but instead it returns an instance of `StockDataFrame`, and it applies `date_col` to the newly-appended row(s) if possible.

### stock.directive_stringify(directive: str) -> str

> Since 0.26.0

Gets the full name of the `directive` which is also the actual column name of the data frame

```py
stock.directive_stringify('kdj.j')
# "kdj.j:9,3,3,50.0"
```

And also

```py
from stock_pandas import

directive_stringify('kdj.j')
# "kdj.j:9,3,3,50.0"
```

Actually, `directive_stringify` does not rely on StockDataFrame instances.

### stock.rolling_calc(size, on, apply, forward, fill) -> np.ndarray

> Since 0.27.0

Applies a 1-D function along the given column or directive `on`

- **size** `int` the size of the rolling window
- **on** `str | Directive` along which the function should be applied
- **apply** `Callable[[np.ndarray], Any]` the 1-D function to apply
- **forward?** `bool = False` whether we should look backward (default value) to get each rolling window or not
- **fill?** `Any = np.nan` the value used to fill where there are not enough items to form a rolling window

```py
stock.rolling_calc(5, 'open', max)

# Whose return value equals to
stock['hhv:5,open'].to_numpy()
```

### stock.cumulate() -> StockDataFrame

Cumulate the current data frame `stock` based on its time frame setting

```py
StockDataFrame(one_minute_kline_data_frame, time_frame='5m').cumulate()

# And you will get a 5-minute kline data
```

see [Cumulation and DatetimeIndex][cumulation] for details

### stock.cum_append(other: DataFrame) -> StockDataFrame

Append `other` to the end of the current data frame `stock` and apply cumulation on them. And the following slice of code is equivalent to the above one:

```py
StockDataFrame(time_frame='5m').cum_append(one_minute_kline_data_frame)
```

see [Cumulation and DatetimeIndex][cumulation] for details


### stock.fulfill() -> self

> Since 1.2.0

Fulfill all stock indicator columns. By default, adding new rows to a `StockDataFrame` will not update stock indicators of the new row.

Stock indicators will only be updated when accessing the stock indicator column or calling `stock.fulfill()`

Check the [test cases](https://github.com/kaelzhang/stock-pandas/blob/master/test/test_fulfill.py) for details

### directive_stringify(directive_str) -> str

> since 0.30.0

Similar to `stock.directive_stringify()` but could be called without class initialization

```py
from stock_pandas import directive_stringify

directive_stringify('boll')
# boll:21,close
```

## Cumulation and DatetimeIndex

Suppose we have a csv file containing kline data of a stock in 1-minute time frame

```py
csv = pd.read_csv(csv_path)

print(csv)
```

```
                   date   open   high    low  close    volume
0   2020-01-01 00:00:00  329.4  331.6  327.6  328.8  14202519
1   2020-01-01 00:01:00  330.0  332.0  328.0  331.0  13953191
2   2020-01-01 00:02:00  332.8  332.8  328.4  331.0  10339120
3   2020-01-01 00:03:00  332.0  334.2  330.2  331.0   9904468
4   2020-01-01 00:04:00  329.6  330.2  324.9  324.9  13947162
5   2020-01-01 00:04:00  329.6  330.2  324.8  324.8  13947163    <- There is an update of
                                                                    2020-01-01 00:04:00
...
16  2020-01-01 00:16:00  333.2  334.8  331.2  334.0  12428539
17  2020-01-01 00:17:00  333.0  333.6  326.8  333.6  15533405
18  2020-01-01 00:18:00  335.0  335.2  326.2  327.2  16655874
19  2020-01-01 00:19:00  327.0  327.2  322.0  323.0  15086985
```

> Noted that duplicated records of a same timestamp will not be cumulated. The records except the latest one will be disgarded.


```py
stock = StockDataFrame(
    csv,
    date_col='date',
    # Which is equivalent to `time_frame=TimeFrame.M5`
    time_frame='5m'
)

print(stock)
```

```
                      open   high    low  close    volume
2020-01-01 00:00:00  329.4  331.6  327.6  328.8  14202519
2020-01-01 00:01:00  330.0  332.0  328.0  331.0  13953191
2020-01-01 00:02:00  332.8  332.8  328.4  331.0  10339120
2020-01-01 00:03:00  332.0  334.2  330.2  331.0   9904468
2020-01-01 00:04:00  329.6  330.2  324.9  324.9  13947162
2020-01-01 00:04:00  329.6  330.2  324.8  324.8  13947162
...
2020-01-01 00:16:00  333.2  334.8  331.2  334.0  12428539
2020-01-01 00:17:00  333.0  333.6  326.8  333.6  15533405
2020-01-01 00:18:00  335.0  335.2  326.2  327.2  16655874
2020-01-01 00:19:00  327.0  327.2  322.0  323.0  15086985
```

You must have figured it out that the data frame now has [`DatetimeIndex`es][datetimeindex].

But it will not become a 15-minute kline data unless we cumulate it, and only cumulates new frames if you use `stock.cum_append(them)` to cumulate `them`.

```py
stock_15m = stock.cumulate()

print(stock_15m)
```

Now we get a 15-minute kline

```
                      open   high    low  close      volume
2020-01-01 00:00:00  329.4  334.2  324.8  324.8  62346461.0
2020-01-01 00:05:00  325.0  327.8  316.2  322.0  82176419.0
2020-01-01 00:10:00  323.0  327.8  314.6  327.6  74409815.0
2020-01-01 00:15:00  330.0  335.2  322.0  323.0  82452902.0
```

For more details and about how to get full control of everything, check the online Google Colab notebook here.

## Syntax of `directive`

```ebnf
directive := command | command operator expression
operator := '/' | '\' | '><' | '<' | '<=' | '==' | '>=' | '>'
expression := float | command

command := command_name | command_name : arguments
command_name := main_command_name | main_command_name.sub_command_name
main_command_name := alphabets
sub_command_name := alphabets

arguments := argument | argument , arguments
argument := empty_string | string | ( directive )
```

#### `directive` Example

Here lists several use cases of column names

```py
# The middle band of bollinger bands
#   which is actually a 20-period (default) moving average
stock['boll']

# kdj j less than 0
# This returns a series of bool type
stock['kdj.j < 0']

# kdj %K cross up kdj %D
stock['kdj.k / kdj.d']

# 5-period simple moving average
stock['ma:5']

# 10-period simple moving average on open prices
stock['ma:10,open']

# Dataframe of 5-period, 10-period, 30-period ma
stock[[
    'ma:5',
    'ma:10',
    'ma:30'
]]

# Which means we use the default values of the first and the second parameters,
# and specify the third parameter
stock['macd:,,10']

# We must wrap a parameter which is a nested command or directive
stock['increase:(ma:20,close),3']

# stock-pandas has a powerful directive parser,
# so we could even write directives like this:
stock['''
repeat
    :
        (
            column:close > boll.upper
        ),
        5
''']
```

## Built-in Commands of Indicators

Document syntax explanation:

- **param0** `int` which means `param0` is a required parameter of type `int`.
- **param1?** `str='close'` which means parameter `param1` is optional with default value `'close'`.

Actually, all parameters of a command are of string type, so the `int` here means an interger-like string.

### `ma`, simple Moving Averages

```
ma:<period>,<column>
```

Gets the `period`-period simple moving average on column named `column`.

`SMA` is often confused between simple moving average and smoothed moving average.

So `stock-pandas` will use `ma` for simple moving average and `smma` for smoothed moving average.

- **period** `int` (required)
- **column?** `enum<'open'|'high'|'low'|'close'>='close'` Which column should the calculation based on. Defaults to `'close'`

```py
# which is equivalent to `stock['ma:5,close']`
stock['ma:5']

stock['ma:10,open']
```

### `ema`, Exponential Moving Average

```
ema:<period>,<column>
```

Gets the Exponential Moving Average, also known as the Exponential Weighted Moving Average.

The arguments of this command is the same as `ma`.

### `macd`, Moving Average Convergence Divergence

```
macd:<fast_period>,<slow_period>
macd.signal:<fast_period>,<slow_period>,<signal_period>
macd.histogram:<fast_period>,<slow_period>,<signal_period>
```

- **fast_period?** `int=12` fast period (short period). Defaults to `12`.
- **slow_period?** `int=26` slow period (long period). Defaults to `26`
- **signal_period?** `int=9` signal period. Defaults to `9`

```py
# macd
stock['macd']
stock['macd.dif']

# macd signal band, which is a shortcut for stock['macd.signal']
stock['macd.s']
stock['macd.signal']
stock['macd.dea']

# macd histogram band, which is equivalent to stock['macd.h']
stock['macd.histogram']
stock['macd.h']
stock['macd.macd']
```

### `boll`, BOLLinger bands

```
boll:<period>,<column>
boll.upper:<period>,<times>,<column>
boll.lower:<period>,<times>,<column>
```

- **period?** `int=20`
- **times?** `float=2.`
- **column?** `str='close'`

```py
# boll
stock['boll']

# bollinger upper band, a shortcut for stock['boll.upper']
stock['boll.u']
stock['boll.upper']

# bollinger lower band, which is equivalent to stock['boll.l']
stock['boll.lower']
stock['boll.l']
```

### `rsv`, Raw Stochastic Value

```
rsv:<period>
```

Calculates the raw stochastic value which is often used to calculate KDJ

### `kdj`, a variety of stochastic oscillator

The variety of [Stochastic Oscillator](https://en.wikipedia.org/wiki/Stochastic_oscillator) indicator created by [Dr. George Lane](https://en.wikipedia.org/wiki/George_Lane_(technical_analyst)), which follows the formula:

```
RSV = rsv(period_rsv)
%K = ema(RSV, period_k)
%D = ema(%K, period_d)
%J = 3 * %K - 2 * %D
```

And the `ema` here is the exponential weighted moving average with initial value as `init_value`.

PAY ATTENTION that the calculation forumla is different from wikipedia, but it is much popular and more widely used by the industry.

**Directive Arguments**:

```
kdj.k:<period_rsv>,<period_k>,<init_value>
kdj.d:<period_rsv>,<period_k>,<period_d>,<init_value>
kdj.j:<period_rsv>,<period_k>,<period_d>,<init_value>
```

- **period_rsv?** `int=9` The period for calculating RSV, which is used for K%
- **period_k?** `int=3` The period for calculating the EMA of RSV, which is used for K%
- **period_d?** `int=3` The period for calculating the EMA of K%, which is used for D%
- **init_value?** `float=50.0` The initial value for calculating ema. Trading softwares of different companies usually use different initial values each of which is usually `0.0`, `50.0` or `100.0`.

```py
# The %D series of KDJ
stock['kdj.d']
# which is equivalent to
stock['kdj.d:9,3,3,50.0']

# The KDJ serieses of with parameters 9, 9, and 9
stock[['kdj.k:9,9', 'kdj.d:9,9,9', 'kdj.j:9,9,9']]
```

### `kdjc`, another variety of stochastic oscillator

Unlike `kdj`, `kdjc` uses **close** value instead of high and low value to calculate `rsv`, which makes the indicator more sensitive than `kdj`

The arguments of `kdjc` are the same as `kdj`

### `rsi`, Relative Strength Index

```
rsi:<period>
```

Calculates the N-period RSI (Relative Strength Index)

- **period** `int` The period to calculate RSI. `period` should be an int which is larger than `1`

### `bbi`, Bull and Bear Index

```
bbi:<a>,<b>,<c>,<d>
```

Calculates indicator BBI (Bull and Bear Index) which is the average of `ma:3`, `ma:6`, `ma:12`, `ma:24` by default

- **a?** `int=3`
- **b?** `int=6`
- **c?** `int=12`
- **d?** `int=24`

### `llv`, Lowest of Low Values

```
llv:<period>,<column>
```

Gets the lowest of low prices in N periods

- **period** `int`
- **column?** `str='low'` Defaults to `'low'`. But you could also get the lowest value of close prices

```py
# The 10-period lowest prices
stock['llv:10']

# The 10-period lowest close prices
stock['llv:10,close']
```

### `hhv`, Highest of High Values

```
hhv:<period>,<column>
```

Gets the highest of high prices in N periods. The arguments of `hhv` is the same as `llv`

## Built-in Commands for Statistics

### `column`

```
column:<name>
```

Just gets the series of a column. This command is designed to be used together with an operator to compare with another command or as a parameter of some statistics command.

- **name** `str` the name of the column

```py
# A bool-type series indicates whether the current price is higher than the upper bollinger band
stock['column:close > boll.upper']
```

### `increase`

```
increase:<on>,<repeat>,<step>
```

Gets a `bool`-type series each item of which is `True` if the value of indicator `on` increases in the last `period`-period.

- **on** `str` the command name of an indicator on what the calculation should be based
- **repeat?** `int=1`
- **direction?** `1 | -1` the direction of "increase". `-1` means decreasing

For example:

```py
# Which means whether the `ma:20,close` line
# (a.k.a. 20-period simple moving average on column `'close'`)
# has been increasing repeatedly for 3 times (maybe 3 days)
stock['increase:(ma:20,close),3']

# If the close price has been decreasing repeatedly for 5 times (maybe 5 days)
stock['increase:close,5,-1']
```

### `style`

```
style:<style>
```

Gets a `bool`-type series whether the candlestick of a period is of `style` style

- **style** `'bullish' | 'bearish'`

```py
stock['style:bullish']
```

### `repeat`

```
repeat:(<bool_directive>),<repeat>
```

The `repeat` command first gets the result of directive `bool_directive`, and detect whether `True` is repeated for `repeat` times

- **bool_directive** `str` the directive which should returns a series of `bool`s. PAY ATTENTION, that the directive should be wrapped with parantheses as a parameter.
- **repeat?** `int=1` which should be larger than `0`

```py
# Whether the bullish candlestick repeats for 3 periods (maybe 3 days)
stock['repeat:(style:bullish),3']
```

### `change`

```
change:<on>,<period>
```

Percentage change between the current and a prior element on a certain series

Computes the percentage change from the immediately previous element by default. This is useful in comparing the percentage of change in a time series of prices.

- **on** `str` the directive which returns a series of numbers, and the calculation will based on the series.
- **period?** `int=2` `2` means we computes with the start value and the end value of a 2-period window.

```py
# Percentage change of 20-period simple moving average
stock['change:(ma:20)']
```

## Operators

```
left operator right
```

### Operator: `/`

whether `left` crosses through `right` from the down side of `right` to the upper side which we call it as "cross up".

### Operator: `\`

whether `left` crosses down `right`.

```py
# Which we call them "dead crosses"
stock['macd \\ macd.signal']
```

**PAY ATTENTION**, in the example above, we should escape the backslash, so we've got double backslashes `'\\'`

### Operator: `><`

whether `left` crosses `right`, either up or down.

### Operator: `<` | `<=` | `==` | `>=` | `>`

For a certain record of the same time, whether the value of `left` is less than / less than or equal to / equal to / larger than or equal to / larger than the value of `right`.

## Errors

```py
from stock_pandas import (
    DirectiveSyntaxError,
    DirectiveValueError
)
```

### `DirectiveSyntaxError`

Raises if there is a syntax error in the given directive.

```py
stock['''
repeat
    :
        (
            column:close >> boll.upper
        ),
        5
''']
```

`DirectiveSyntaxError` might print some messages like this:

```
File "<string>", line 5, column 26

   repeat
       :
           (
>              column:close >> boll.upper
           ),
           5

                            ^
DirectiveSyntaxError: ">>" is an invalid operator
```

### `DirectiveValueError`

Raises if
- there is an unknown command name
- something is wrong about the command arguments
- etc.

****

## Advanced Sections

> How to extend stock-pandas and support more indicators,

> This section is only recommended for contributors, but not for normal users, for that the definition of `COMMANDS` might change in the future.

```py
from stock_pandas import COMMANDS, CommandPreset
```

To add a new indicator to stock-pandas, you could update the `COMMANDS` dict.

```py
# The value of 'new-indicator' is a tuple
COMMANDS['new-indicator'] = (
    # The first item of the tuple is a CommandPreset instance
    CommandPreset(
        formula,
        args_setting
    ),
    sub_commands_dict,
    aliases_of_sub_commands
)
```

You could check [here](https://github.com/kaelzhang/stock-pandas/blob/master/stock_pandas/commands/base.py#L54) to figure out the typings for `COMMANDS`.

For a simplest indicator, such as simple moving average, you could check the implementation [here](https://github.com/kaelzhang/stock-pandas/blob/master/stock_pandas/commands/trend_following.py#L60).

### formula(df, s, *args) -> Tuple[np.ndarray, int]

`formula` is a `Callable[[StockDataFrame, slice, ...], [ndarray, int]]`.

- **df** `StockDataFrame` the first argument of `formula` is the stock dataframe itself
- **s** `slice` sometimes, we don't need to calculate the whole dataframe but only part of it. This argument is passed into the formula by `stock_pandas` and should not be changed manually.
- **args** `Tuple[Any]` the args of the indicator which is defined by `args_setting`

The Callable returns a tuple:
- The first item of the tuple is the calculated result which is a numpy ndarray.
- The second item of the tuple is the mininum periods to calculate the indicator.

### args_setting: [(default, validate_and_coerce), ...]

`args_setting` is a list of tuples.

- The first item of each tuple is the default value of the parameter, and it could be `None` which implies it has no default value and is required.

- The second item is a raisable callable which receives user input, validates it, coerces the type of the value and returns it. If the parameter has a default value and user don't specified a value, the function will be skipped.

### sub_commands_dict: Dict[str, CommandPreset]

A dict to declare sub commands, such as `boll.upper`.

`sub_commands_dict` could be `None` which indicates the indicator has no sub commands

### aliases_of_sub_commands: Dict[str, Optional[str]]

Which declares the shortcut or alias of the commands, such as `boll.u`

```py
dict(
    u='upper'
)
```

If the value of an alias is `None`, which means it is an alias of the main command, such as `macd.dif`

```py
dict(
    dif=None
)
```

## Development

First, install conda (recommended), and generate a conda environment for this project

```sh
conda create -n stock-pandas python=3.11

conda activate stock-pandas

# Install requirements
make install

# Build python ext (C++)
make build-ext

# Run unit tests
make test
```



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/kaelzhang/stock-pandas",
    "name": "stock-pandas",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.6",
    "maintainer_email": "",
    "keywords": "pandas pandas-dataframe stock stat indicators macd",
    "author": "Kael Zhang",
    "author_email": "i+pypi@kael.me",
    "download_url": "https://files.pythonhosted.org/packages/a8/09/72f88a0922439e74a8cb570f8e747caef1a3a73925af02061f56e1bc9e5b/stock-pandas-1.2.0.tar.gz",
    "platform": null,
    "description": "[![](https://travis-ci.org/kaelzhang/stock-pandas.svg?branch=master)](https://travis-ci.org/kaelzhang/stock-pandas)\n[![](https://codecov.io/gh/kaelzhang/stock-pandas/branch/master/graph/badge.svg)](https://codecov.io/gh/kaelzhang/stock-pandas)\n[![](https://img.shields.io/pypi/v/stock-pandas.svg)](https://pypi.org/project/stock-pandas/)\n[![](https://img.shields.io/pypi/l/stock-pandas.svg)](https://github.com/kaelzhang/stock-pandas)\n\n\n[ma]: #ma-simple-moving-averages\n[ema]: #ema-exponential-moving-average\n[macd]: #macd-moving-average-convergence-divergence\n[boll]: #boll-bollinger-bands\n[rsv]: #rsv-raw-stochastic-value\n[kdj]: #kdj-a-variety-of-stochastic-oscillator\n[kdj]: #kdjc-another-variety-of-stochastic-oscillator\n[rsi]: #rsi-relative-strength-index\n[bbi]: #bbi-bull-and-bear-index\n[llv]: #llv-lowest-of-low-values\n[hhv]: #hhv-highest-of-high-values\n[column]: #column\n[increase]: #increase\n[style]: #style\n[repeat]: #repeat\n[change]: #change\n[cumulation]: #cumulation-and-datetimeindex\n[datetimeindex]: https://pandas.pydata.org/docs/reference/api/pandas.DatetimeIndex.html\n\n\n# [stock-pandas](https://github.com/kaelzhang/stock-pandas)\n\n**stock-pandas** inherits and extends `pandas.DataFrame` to support:\n- Stock Statistics\n- Stock Indicators, including:\n  - Trend-following momentum indicators, such as [**MA**][ma], [**EMA**][ema], [**MACD**][macd], [**BBI**][bbi]\n  - Dynamic support and resistance indicators, such as [**BOLL**][boll]\n  - Over-bought / over-sold indicators, such as [**KDJ**][kdj], [**RSI**][rsi]\n  - Other indicators, such as [**LLV**][llv], [**HHV**][hhv]\n  - For more indicators, welcome to [request a proposal](https://github.com/kaelzhang/stock-pandas/issues/new?assignees=&labels=feature&template=FEATURE_REQUEST.md&title=), or fork and send me a pull request, or extend stock-pandas yourself. You might read the [Advanced Sections](https://github.com/kaelzhang/stock-pandas#advanced-sections) below.\n- To [cumulate][cumulation] kline data based on a given time frame, so that it could easily handle real-time data updates.\n\n`stock-pandas` makes automatical trading much easier. `stock-pandas` requires Python >= **3.6** and Pandas >= **1.0.0**(for now)\n\nWith the help of `stock-pandas` and mplfinance, we could easily draw something like:\n\n![](boll.png)\n\nThe code example is available at [here](https://github.com/kaelzhang/stock-pandas-examples/blob/master/example/bollinger_bands.ipynb).\n\n## Install\n\nFor now, before installing `stock-pandas` in your environment\n\n#### Have `g++` compiler installed\n\n```sh\n# With yum, for CentOS, Amazon Linux, etc\nyum install gcc-c++\n\n# With apt-get, for Ubuntu\napt-get install g++\n\n# For macOS, install XCode commandline tools\nxcode-select --install\n```\n\nIf you use docker with `Dockerfile` and use python image,\n\n```Dockerfile\nFROM python:3.8\n\n...\n```\n\nThe default `python:3.8` image already contains g++, so we do not install g++ additionally.\n\n#### Install `stock-pandas`\n\n```sh\n# Installing `stock-pandas` requires `numpy` to be installed first\npip install numpy\n\npip install stock-pandas\n```\n\nBe careful, you still need to install `numpy` explicitly even if `numpy` and `stock-pandas` both are contained in `requirement.txt`\n\n```txt\nnumpy\nstock-pandas\nother-dependencies\n...\n```\n\n```sh\npip install numpy\n\npip install -r requirement.txt\n```\n\n## Usage\n\n```py\nfrom stock_pandas import StockDataFrame\n\n# or\nimport stock_pandas as spd\n```\n\nWe also have some examples with annotations in the [`example`](https://github.com/kaelzhang/stock-pandas/tree/master/example) directory, you could use [JupyterLab](https://jupyter.org/) or Jupyter notebook to play with them.\n\n### StockDataFrame\n\n`StockDataFrame` inherits from `pandas.DataFrame`, so if you are familiar with `pandas.DataFrame`, you are already ready to use `stock-pandas`\n\n```py\nimport pandas as pd\nstock = StockDataFrame(pd.read_csv('stock.csv'))\n```\n\nAs we know, we could use `[]`, which called **pandas indexing** (a.k.a. `__getitem__` in python) to select out lower-dimensional slices. In addition to indexing with `colname` (column name of the `DataFrame`), we could also do indexing by `directive`s.\n\n```py\nstock[directive] # Gets a pandas.Series\n\nstock[[directive0, directive1]] # Gets a StockDataFrame\n```\n\nWe have an example to show the most basic indexing using `[directive]`\n\n```py\nstock = StockDataFrame({\n    'open' : ...,\n    'high' : ...,\n    'low'  : ...,\n    'close': [5, 6, 7, 8, 9]\n})\n\nstock['ma:2']\n\n# 0    NaN\n# 1    5.5\n# 2    6.5\n# 3    7.5\n# 4    8.5\n# Name: ma:2,close, dtype: float64\n```\n\nWhich prints the 2-period simple moving average on column `\"close\"`.\n\n#### Parameters\n\n- **date_col** `Optional[str] = None` If set, then the column named `date_col` will convert and set as [`DateTimeIndex`](datetimeindex) of the data frame\n- **to_datetime_kwargs** `dict = {}` the keyworded arguments to be passed to `pandas.to_datetime()`. It only takes effect if `date_col` is specified.\n- **time_frame** `str | TimeFrame | None = None` time frame of the stock. For now, only the following time frames are supported:\n    - `'1m'` or `TimeFrame.M1`\n    - `'3m'` or `TimeFrame.M3`\n    - `'5m'` or `TimeFrame.M5`\n    - `'15m'` or `TimeFrame.M15`\n    - `'30m'` or `TimeFrame.M30`\n    - `'1h'` or `TimeFrame.H1`\n    - `'2h'` or `TimeFrame.H2`\n    - `'4h'` or `TimeFrame.H4`\n    - `'6h'` or `TimeFrame.H6`\n    - `'8h'` or `TimeFrame.H8`\n    - `'12h'` or `TimeFrame.H12`\n\n### stock.exec(directive: str, create_column: bool=False) -> np.ndarray\n\nExecutes the given directive and returns a numpy ndarray according to the directive.\n\n```py\nstock['ma:5'] # returns a Series\n\nstock.exec('ma:5', create_column=True) # returns a numpy ndarray\n```\n\n```py\n# This will only calculate without creating a new column in the dataframe\nstock.exec('ma:20')\n```\n\nThe difference between `stock[directive]` and `stock.exec(directive)` is that\n- the former will create a new column for the result of `directive` as a cache for later use, while `stock.exec(directive)` does not unless we pass the parameter `create_column` as `True`\n- the former one accepts other pandas indexing targets, while `stock.exec(directive)` only accepts a valid **stock-pandas** directive string\n- the former one returns a `pandas.Series` or `StockDataFrame` object while the latter one returns an [`np.ndarray`](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.html)\n\n### stock.alias(alias: str, name: str) -> None\n\nDefines column alias or directive alias\n\n- **alias** `str` the alias name\n- **name** `str` the name of an existing column or the directive string\n\n```py\n# Some plot library such as `mplfinance` requires a column named capitalized `Open`,\n# but it is ok, we could create an alias.\nstock.alias('Open', 'open')\n\nstock.alias('buy_point', 'kdj.j < 0')\n```\n\n### stock.get_column(key: str) -> pd.Series\n\nDirectly gets the column value by `key`, returns a pandas `Series`.\n\nIf the given `key` is an alias name, it will return the value of corresponding original column.\n\nIf the column is not found, a `KeyError` will be raised.\n\n```py\nstock = StockDataFrame({\n    'open' : ...,\n    'high' : ...,\n    'low'  : ...,\n    'close': [5, 6, 7, 8, 9]\n})\n\nstock.get_column('close')\n# 0    5\n# 1    6\n# 2    7\n# 3    8\n# 4    9\n# Name: close, dtype: float64\n```\n\n```py\ntry:\n    stock.get_column('Close')\nexcept KeyError as e:\n    print(e)\n\n    # KeyError: column \"Close\" not found\n\nstock.alias('Close', 'close')\n\nstock.get_column('Close')\n# The same as `stock.get_column('close')`\n```\n\n### stock.append(other, *args, **kwargs) -> StockDataFrame\n\nAppends rows of `other` to the end of caller, returning a new object.\n\nThis method has nearly the same hehavior of [`pandas.DataFrame.append()`](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.append.html), but instead it returns an instance of `StockDataFrame`, and it applies `date_col` to the newly-appended row(s) if possible.\n\n### stock.directive_stringify(directive: str) -> str\n\n> Since 0.26.0\n\nGets the full name of the `directive` which is also the actual column name of the data frame\n\n```py\nstock.directive_stringify('kdj.j')\n# \"kdj.j:9,3,3,50.0\"\n```\n\nAnd also\n\n```py\nfrom stock_pandas import\n\ndirective_stringify('kdj.j')\n# \"kdj.j:9,3,3,50.0\"\n```\n\nActually, `directive_stringify` does not rely on StockDataFrame instances.\n\n### stock.rolling_calc(size, on, apply, forward, fill) -> np.ndarray\n\n> Since 0.27.0\n\nApplies a 1-D function along the given column or directive `on`\n\n- **size** `int` the size of the rolling window\n- **on** `str | Directive` along which the function should be applied\n- **apply** `Callable[[np.ndarray], Any]` the 1-D function to apply\n- **forward?** `bool = False` whether we should look backward (default value) to get each rolling window or not\n- **fill?** `Any = np.nan` the value used to fill where there are not enough items to form a rolling window\n\n```py\nstock.rolling_calc(5, 'open', max)\n\n# Whose return value equals to\nstock['hhv:5,open'].to_numpy()\n```\n\n### stock.cumulate() -> StockDataFrame\n\nCumulate the current data frame `stock` based on its time frame setting\n\n```py\nStockDataFrame(one_minute_kline_data_frame, time_frame='5m').cumulate()\n\n# And you will get a 5-minute kline data\n```\n\nsee [Cumulation and DatetimeIndex][cumulation] for details\n\n### stock.cum_append(other: DataFrame) -> StockDataFrame\n\nAppend `other` to the end of the current data frame `stock` and apply cumulation on them. And the following slice of code is equivalent to the above one:\n\n```py\nStockDataFrame(time_frame='5m').cum_append(one_minute_kline_data_frame)\n```\n\nsee [Cumulation and DatetimeIndex][cumulation] for details\n\n\n### stock.fulfill() -> self\n\n> Since 1.2.0\n\nFulfill all stock indicator columns. By default, adding new rows to a `StockDataFrame` will not update stock indicators of the new row.\n\nStock indicators will only be updated when accessing the stock indicator column or calling `stock.fulfill()`\n\nCheck the [test cases](https://github.com/kaelzhang/stock-pandas/blob/master/test/test_fulfill.py) for details\n\n### directive_stringify(directive_str) -> str\n\n> since 0.30.0\n\nSimilar to `stock.directive_stringify()` but could be called without class initialization\n\n```py\nfrom stock_pandas import directive_stringify\n\ndirective_stringify('boll')\n# boll:21,close\n```\n\n## Cumulation and DatetimeIndex\n\nSuppose we have a csv file containing kline data of a stock in 1-minute time frame\n\n```py\ncsv = pd.read_csv(csv_path)\n\nprint(csv)\n```\n\n```\n                   date   open   high    low  close    volume\n0   2020-01-01 00:00:00  329.4  331.6  327.6  328.8  14202519\n1   2020-01-01 00:01:00  330.0  332.0  328.0  331.0  13953191\n2   2020-01-01 00:02:00  332.8  332.8  328.4  331.0  10339120\n3   2020-01-01 00:03:00  332.0  334.2  330.2  331.0   9904468\n4   2020-01-01 00:04:00  329.6  330.2  324.9  324.9  13947162\n5   2020-01-01 00:04:00  329.6  330.2  324.8  324.8  13947163    <- There is an update of\n                                                                    2020-01-01 00:04:00\n...\n16  2020-01-01 00:16:00  333.2  334.8  331.2  334.0  12428539\n17  2020-01-01 00:17:00  333.0  333.6  326.8  333.6  15533405\n18  2020-01-01 00:18:00  335.0  335.2  326.2  327.2  16655874\n19  2020-01-01 00:19:00  327.0  327.2  322.0  323.0  15086985\n```\n\n> Noted that duplicated records of a same timestamp will not be cumulated. The records except the latest one will be disgarded.\n\n\n```py\nstock = StockDataFrame(\n    csv,\n    date_col='date',\n    # Which is equivalent to `time_frame=TimeFrame.M5`\n    time_frame='5m'\n)\n\nprint(stock)\n```\n\n```\n                      open   high    low  close    volume\n2020-01-01 00:00:00  329.4  331.6  327.6  328.8  14202519\n2020-01-01 00:01:00  330.0  332.0  328.0  331.0  13953191\n2020-01-01 00:02:00  332.8  332.8  328.4  331.0  10339120\n2020-01-01 00:03:00  332.0  334.2  330.2  331.0   9904468\n2020-01-01 00:04:00  329.6  330.2  324.9  324.9  13947162\n2020-01-01 00:04:00  329.6  330.2  324.8  324.8  13947162\n...\n2020-01-01 00:16:00  333.2  334.8  331.2  334.0  12428539\n2020-01-01 00:17:00  333.0  333.6  326.8  333.6  15533405\n2020-01-01 00:18:00  335.0  335.2  326.2  327.2  16655874\n2020-01-01 00:19:00  327.0  327.2  322.0  323.0  15086985\n```\n\nYou must have figured it out that the data frame now has [`DatetimeIndex`es][datetimeindex].\n\nBut it will not become a 15-minute kline data unless we cumulate it, and only cumulates new frames if you use `stock.cum_append(them)` to cumulate `them`.\n\n```py\nstock_15m = stock.cumulate()\n\nprint(stock_15m)\n```\n\nNow we get a 15-minute kline\n\n```\n                      open   high    low  close      volume\n2020-01-01 00:00:00  329.4  334.2  324.8  324.8  62346461.0\n2020-01-01 00:05:00  325.0  327.8  316.2  322.0  82176419.0\n2020-01-01 00:10:00  323.0  327.8  314.6  327.6  74409815.0\n2020-01-01 00:15:00  330.0  335.2  322.0  323.0  82452902.0\n```\n\nFor more details and about how to get full control of everything, check the online Google Colab notebook here.\n\n## Syntax of `directive`\n\n```ebnf\ndirective := command | command operator expression\noperator := '/' | '\\' | '><' | '<' | '<=' | '==' | '>=' | '>'\nexpression := float | command\n\ncommand := command_name | command_name : arguments\ncommand_name := main_command_name | main_command_name.sub_command_name\nmain_command_name := alphabets\nsub_command_name := alphabets\n\narguments := argument | argument , arguments\nargument := empty_string | string | ( directive )\n```\n\n#### `directive` Example\n\nHere lists several use cases of column names\n\n```py\n# The middle band of bollinger bands\n#   which is actually a 20-period (default) moving average\nstock['boll']\n\n# kdj j less than 0\n# This returns a series of bool type\nstock['kdj.j < 0']\n\n# kdj %K cross up kdj %D\nstock['kdj.k / kdj.d']\n\n# 5-period simple moving average\nstock['ma:5']\n\n# 10-period simple moving average on open prices\nstock['ma:10,open']\n\n# Dataframe of 5-period, 10-period, 30-period ma\nstock[[\n    'ma:5',\n    'ma:10',\n    'ma:30'\n]]\n\n# Which means we use the default values of the first and the second parameters,\n# and specify the third parameter\nstock['macd:,,10']\n\n# We must wrap a parameter which is a nested command or directive\nstock['increase:(ma:20,close),3']\n\n# stock-pandas has a powerful directive parser,\n# so we could even write directives like this:\nstock['''\nrepeat\n    :\n        (\n            column:close > boll.upper\n        ),\n        5\n''']\n```\n\n## Built-in Commands of Indicators\n\nDocument syntax explanation:\n\n- **param0** `int` which means `param0` is a required parameter of type `int`.\n- **param1?** `str='close'` which means parameter `param1` is optional with default value `'close'`.\n\nActually, all parameters of a command are of string type, so the `int` here means an interger-like string.\n\n### `ma`, simple Moving Averages\n\n```\nma:<period>,<column>\n```\n\nGets the `period`-period simple moving average on column named `column`.\n\n`SMA` is often confused between simple moving average and smoothed moving average.\n\nSo `stock-pandas` will use `ma` for simple moving average and `smma` for smoothed moving average.\n\n- **period** `int` (required)\n- **column?** `enum<'open'|'high'|'low'|'close'>='close'` Which column should the calculation based on. Defaults to `'close'`\n\n```py\n# which is equivalent to `stock['ma:5,close']`\nstock['ma:5']\n\nstock['ma:10,open']\n```\n\n### `ema`, Exponential Moving Average\n\n```\nema:<period>,<column>\n```\n\nGets the Exponential Moving Average, also known as the Exponential Weighted Moving Average.\n\nThe arguments of this command is the same as `ma`.\n\n### `macd`, Moving Average Convergence Divergence\n\n```\nmacd:<fast_period>,<slow_period>\nmacd.signal:<fast_period>,<slow_period>,<signal_period>\nmacd.histogram:<fast_period>,<slow_period>,<signal_period>\n```\n\n- **fast_period?** `int=12` fast period (short period). Defaults to `12`.\n- **slow_period?** `int=26` slow period (long period). Defaults to `26`\n- **signal_period?** `int=9` signal period. Defaults to `9`\n\n```py\n# macd\nstock['macd']\nstock['macd.dif']\n\n# macd signal band, which is a shortcut for stock['macd.signal']\nstock['macd.s']\nstock['macd.signal']\nstock['macd.dea']\n\n# macd histogram band, which is equivalent to stock['macd.h']\nstock['macd.histogram']\nstock['macd.h']\nstock['macd.macd']\n```\n\n### `boll`, BOLLinger bands\n\n```\nboll:<period>,<column>\nboll.upper:<period>,<times>,<column>\nboll.lower:<period>,<times>,<column>\n```\n\n- **period?** `int=20`\n- **times?** `float=2.`\n- **column?** `str='close'`\n\n```py\n# boll\nstock['boll']\n\n# bollinger upper band, a shortcut for stock['boll.upper']\nstock['boll.u']\nstock['boll.upper']\n\n# bollinger lower band, which is equivalent to stock['boll.l']\nstock['boll.lower']\nstock['boll.l']\n```\n\n### `rsv`, Raw Stochastic Value\n\n```\nrsv:<period>\n```\n\nCalculates the raw stochastic value which is often used to calculate KDJ\n\n### `kdj`, a variety of stochastic oscillator\n\nThe variety of [Stochastic Oscillator](https://en.wikipedia.org/wiki/Stochastic_oscillator) indicator created by [Dr. George Lane](https://en.wikipedia.org/wiki/George_Lane_(technical_analyst)), which follows the formula:\n\n```\nRSV = rsv(period_rsv)\n%K = ema(RSV, period_k)\n%D = ema(%K, period_d)\n%J = 3 * %K - 2 * %D\n```\n\nAnd the `ema` here is the exponential weighted moving average with initial value as `init_value`.\n\nPAY ATTENTION that the calculation forumla is different from wikipedia, but it is much popular and more widely used by the industry.\n\n**Directive Arguments**:\n\n```\nkdj.k:<period_rsv>,<period_k>,<init_value>\nkdj.d:<period_rsv>,<period_k>,<period_d>,<init_value>\nkdj.j:<period_rsv>,<period_k>,<period_d>,<init_value>\n```\n\n- **period_rsv?** `int=9` The period for calculating RSV, which is used for K%\n- **period_k?** `int=3` The period for calculating the EMA of RSV, which is used for K%\n- **period_d?** `int=3` The period for calculating the EMA of K%, which is used for D%\n- **init_value?** `float=50.0` The initial value for calculating ema. Trading softwares of different companies usually use different initial values each of which is usually `0.0`, `50.0` or `100.0`.\n\n```py\n# The %D series of KDJ\nstock['kdj.d']\n# which is equivalent to\nstock['kdj.d:9,3,3,50.0']\n\n# The KDJ serieses of with parameters 9, 9, and 9\nstock[['kdj.k:9,9', 'kdj.d:9,9,9', 'kdj.j:9,9,9']]\n```\n\n### `kdjc`, another variety of stochastic oscillator\n\nUnlike `kdj`, `kdjc` uses **close** value instead of high and low value to calculate `rsv`, which makes the indicator more sensitive than `kdj`\n\nThe arguments of `kdjc` are the same as `kdj`\n\n### `rsi`, Relative Strength Index\n\n```\nrsi:<period>\n```\n\nCalculates the N-period RSI (Relative Strength Index)\n\n- **period** `int` The period to calculate RSI. `period` should be an int which is larger than `1`\n\n### `bbi`, Bull and Bear Index\n\n```\nbbi:<a>,<b>,<c>,<d>\n```\n\nCalculates indicator BBI (Bull and Bear Index) which is the average of `ma:3`, `ma:6`, `ma:12`, `ma:24` by default\n\n- **a?** `int=3`\n- **b?** `int=6`\n- **c?** `int=12`\n- **d?** `int=24`\n\n### `llv`, Lowest of Low Values\n\n```\nllv:<period>,<column>\n```\n\nGets the lowest of low prices in N periods\n\n- **period** `int`\n- **column?** `str='low'` Defaults to `'low'`. But you could also get the lowest value of close prices\n\n```py\n# The 10-period lowest prices\nstock['llv:10']\n\n# The 10-period lowest close prices\nstock['llv:10,close']\n```\n\n### `hhv`, Highest of High Values\n\n```\nhhv:<period>,<column>\n```\n\nGets the highest of high prices in N periods. The arguments of `hhv` is the same as `llv`\n\n## Built-in Commands for Statistics\n\n### `column`\n\n```\ncolumn:<name>\n```\n\nJust gets the series of a column. This command is designed to be used together with an operator to compare with another command or as a parameter of some statistics command.\n\n- **name** `str` the name of the column\n\n```py\n# A bool-type series indicates whether the current price is higher than the upper bollinger band\nstock['column:close > boll.upper']\n```\n\n### `increase`\n\n```\nincrease:<on>,<repeat>,<step>\n```\n\nGets a `bool`-type series each item of which is `True` if the value of indicator `on` increases in the last `period`-period.\n\n- **on** `str` the command name of an indicator on what the calculation should be based\n- **repeat?** `int=1`\n- **direction?** `1 | -1` the direction of \"increase\". `-1` means decreasing\n\nFor example:\n\n```py\n# Which means whether the `ma:20,close` line\n# (a.k.a. 20-period simple moving average on column `'close'`)\n# has been increasing repeatedly for 3 times (maybe 3 days)\nstock['increase:(ma:20,close),3']\n\n# If the close price has been decreasing repeatedly for 5 times (maybe 5 days)\nstock['increase:close,5,-1']\n```\n\n### `style`\n\n```\nstyle:<style>\n```\n\nGets a `bool`-type series whether the candlestick of a period is of `style` style\n\n- **style** `'bullish' | 'bearish'`\n\n```py\nstock['style:bullish']\n```\n\n### `repeat`\n\n```\nrepeat:(<bool_directive>),<repeat>\n```\n\nThe `repeat` command first gets the result of directive `bool_directive`, and detect whether `True` is repeated for `repeat` times\n\n- **bool_directive** `str` the directive which should returns a series of `bool`s. PAY ATTENTION, that the directive should be wrapped with parantheses as a parameter.\n- **repeat?** `int=1` which should be larger than `0`\n\n```py\n# Whether the bullish candlestick repeats for 3 periods (maybe 3 days)\nstock['repeat:(style:bullish),3']\n```\n\n### `change`\n\n```\nchange:<on>,<period>\n```\n\nPercentage change between the current and a prior element on a certain series\n\nComputes the percentage change from the immediately previous element by default. This is useful in comparing the percentage of change in a time series of prices.\n\n- **on** `str` the directive which returns a series of numbers, and the calculation will based on the series.\n- **period?** `int=2` `2` means we computes with the start value and the end value of a 2-period window.\n\n```py\n# Percentage change of 20-period simple moving average\nstock['change:(ma:20)']\n```\n\n## Operators\n\n```\nleft operator right\n```\n\n### Operator: `/`\n\nwhether `left` crosses through `right` from the down side of `right` to the upper side which we call it as \"cross up\".\n\n### Operator: `\\`\n\nwhether `left` crosses down `right`.\n\n```py\n# Which we call them \"dead crosses\"\nstock['macd \\\\ macd.signal']\n```\n\n**PAY ATTENTION**, in the example above, we should escape the backslash, so we've got double backslashes `'\\\\'`\n\n### Operator: `><`\n\nwhether `left` crosses `right`, either up or down.\n\n### Operator: `<` | `<=` | `==` | `>=` | `>`\n\nFor a certain record of the same time, whether the value of `left` is less than / less than or equal to / equal to / larger than or equal to / larger than the value of `right`.\n\n## Errors\n\n```py\nfrom stock_pandas import (\n    DirectiveSyntaxError,\n    DirectiveValueError\n)\n```\n\n### `DirectiveSyntaxError`\n\nRaises if there is a syntax error in the given directive.\n\n```py\nstock['''\nrepeat\n    :\n        (\n            column:close >> boll.upper\n        ),\n        5\n''']\n```\n\n`DirectiveSyntaxError` might print some messages like this:\n\n```\nFile \"<string>\", line 5, column 26\n\n   repeat\n       :\n           (\n>              column:close >> boll.upper\n           ),\n           5\n\n                            ^\nDirectiveSyntaxError: \">>\" is an invalid operator\n```\n\n### `DirectiveValueError`\n\nRaises if\n- there is an unknown command name\n- something is wrong about the command arguments\n- etc.\n\n****\n\n## Advanced Sections\n\n> How to extend stock-pandas and support more indicators,\n\n> This section is only recommended for contributors, but not for normal users, for that the definition of `COMMANDS` might change in the future.\n\n```py\nfrom stock_pandas import COMMANDS, CommandPreset\n```\n\nTo add a new indicator to stock-pandas, you could update the `COMMANDS` dict.\n\n```py\n# The value of 'new-indicator' is a tuple\nCOMMANDS['new-indicator'] = (\n    # The first item of the tuple is a CommandPreset instance\n    CommandPreset(\n        formula,\n        args_setting\n    ),\n    sub_commands_dict,\n    aliases_of_sub_commands\n)\n```\n\nYou could check [here](https://github.com/kaelzhang/stock-pandas/blob/master/stock_pandas/commands/base.py#L54) to figure out the typings for `COMMANDS`.\n\nFor a simplest indicator, such as simple moving average, you could check the implementation [here](https://github.com/kaelzhang/stock-pandas/blob/master/stock_pandas/commands/trend_following.py#L60).\n\n### formula(df, s, *args) -> Tuple[np.ndarray, int]\n\n`formula` is a `Callable[[StockDataFrame, slice, ...], [ndarray, int]]`.\n\n- **df** `StockDataFrame` the first argument of `formula` is the stock dataframe itself\n- **s** `slice` sometimes, we don't need to calculate the whole dataframe but only part of it. This argument is passed into the formula by `stock_pandas` and should not be changed manually.\n- **args** `Tuple[Any]` the args of the indicator which is defined by `args_setting`\n\nThe Callable returns a tuple:\n- The first item of the tuple is the calculated result which is a numpy ndarray.\n- The second item of the tuple is the mininum periods to calculate the indicator.\n\n### args_setting: [(default, validate_and_coerce), ...]\n\n`args_setting` is a list of tuples.\n\n- The first item of each tuple is the default value of the parameter, and it could be `None` which implies it has no default value and is required.\n\n- The second item is a raisable callable which receives user input, validates it, coerces the type of the value and returns it. If the parameter has a default value and user don't specified a value, the function will be skipped.\n\n### sub_commands_dict: Dict[str, CommandPreset]\n\nA dict to declare sub commands, such as `boll.upper`.\n\n`sub_commands_dict` could be `None` which indicates the indicator has no sub commands\n\n### aliases_of_sub_commands: Dict[str, Optional[str]]\n\nWhich declares the shortcut or alias of the commands, such as `boll.u`\n\n```py\ndict(\n    u='upper'\n)\n```\n\nIf the value of an alias is `None`, which means it is an alias of the main command, such as `macd.dif`\n\n```py\ndict(\n    dif=None\n)\n```\n\n## Development\n\nFirst, install conda (recommended), and generate a conda environment for this project\n\n```sh\nconda create -n stock-pandas python=3.11\n\nconda activate stock-pandas\n\n# Install requirements\nmake install\n\n# Build python ext (C++)\nmake build-ext\n\n# Run unit tests\nmake test\n```\n\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "The wrapper of `pandas.DataFrame` with stock statistics and indicators support.",
    "version": "1.2.0",
    "split_keywords": [
        "pandas",
        "pandas-dataframe",
        "stock",
        "stat",
        "indicators",
        "macd"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "410a42e080029f437a69b0f8e0bd8747118648414a9754a5226ecc8185a99254",
                "md5": "eb7182ab5ab73869375c5bd3775b36e3",
                "sha256": "2e0e0804df0cd5768d99106ad7df8d1760556a9f204be570de0315666359068f"
            },
            "downloads": -1,
            "filename": "stock_pandas-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl",
            "has_sig": false,
            "md5_digest": "eb7182ab5ab73869375c5bd3775b36e3",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": ">=3.6",
            "size": 120194,
            "upload_time": "2023-04-07T01:59:40",
            "upload_time_iso_8601": "2023-04-07T01:59:40.910822Z",
            "url": "https://files.pythonhosted.org/packages/41/0a/42e080029f437a69b0f8e0bd8747118648414a9754a5226ecc8185a99254/stock_pandas-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "a80972f88a0922439e74a8cb570f8e747caef1a3a73925af02061f56e1bc9e5b",
                "md5": "0b95fbf4c9e61754049228a988f48a16",
                "sha256": "c54cfe9b89c85bba0feeb0d4fc0081211cd4e3f865f465317d2131a90dc44993"
            },
            "downloads": -1,
            "filename": "stock-pandas-1.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "0b95fbf4c9e61754049228a988f48a16",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.6",
            "size": 164062,
            "upload_time": "2023-04-07T01:59:43",
            "upload_time_iso_8601": "2023-04-07T01:59:43.241853Z",
            "url": "https://files.pythonhosted.org/packages/a8/09/72f88a0922439e74a8cb570f8e747caef1a3a73925af02061f56e1bc9e5b/stock-pandas-1.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-04-07 01:59:43",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "kaelzhang",
    "github_project": "stock-pandas",
    "travis_ci": true,
    "coveralls": false,
    "github_actions": false,
    "requirements": [],
    "lcname": "stock-pandas"
}
        
Elapsed time: 0.05790s