stock-pandas


Namestock-pandas JSON
Version 1.4.6 PyPI version JSON
download
home_pageNone
SummaryThe production-ready subclass of `pandas.DataFrame` to support stock statistics and indicators.
upload_time2024-12-16 13:40:13
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
licenseCopyright (c) 2013 kaelzhang <>, contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            [![](https://github.com/kaelzhang/stock-pandas/actions/workflows/python.yml/badge.svg)](https://github.com/kaelzhang/stock-pandas/actions/workflows/python.yml)
[![](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/)
[![Conda version](https://img.shields.io/conda/vn/conda-forge/stock-pandas)](https://anaconda.org/conda-forge/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 automated trading much easier. `stock-pandas` requires Python >= **3.9** 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.9

...
```

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

#### Install `stock-pandas`

```sh
pip install stock-pandas
```

A [conda-forge recipe](https://github.com/conda-forge/stock-pandas-feedstock) is also available, so you can also use

```sh
conda install -c conda-forge stock-pandas
```

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

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`

### `donchian`, Donchian Channels

```
donchian:<period>,<column_upper>,<column_lower>
donchian.upper:<period>,<column_upper>
donchian.lower:<period>,<column_lower>
```

Gets the Donchian channels

- **period** `int`
- **column_upper?** `str='high'` The column to calculate highest high values, defaults to `'high'`
- **column_lower?** `str='low'` The column to calculate lowest low values, defaults to `'low'`

```py
# Donchian middle channel
stock['donchian']
stock['donchian.middle']

# Donchian upper channel, a shortcut for stock['donchian.upper']
stock['donchian.u']
stock['donchian.upper']

# Donchian lower channel, which is equivalent to stock['donchian.l']
stock['donchian.lower']
stock['donchian.l']
```


## 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.

## About Pandas Copy-on-Write (CoW) Mode

Since `1.3.0`, `stock-pandas` starts to support pandas [copy-on-write mode](https://pandas.pydata.org/pandas-docs/stable/user_guide/copy_on_write.html#copy-on-write-cow)

You could enable pandas copy-on-write mode by using `pd.options.mode.copy_on_write = True`

or using the environment variable:

```sh
export STOCK_PANDAS_COW=1
```

****

## 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.12

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": null,
    "name": "stock-pandas",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": null,
    "author": null,
    "author_email": "Kael Zhang <i+pypi@kael.me>",
    "download_url": "https://files.pythonhosted.org/packages/7e/e2/7d5ba1af07c4941516d313009a6cc61140b850fdbb4d3f3452ce9f82e784/stock_pandas-1.4.6.tar.gz",
    "platform": null,
    "description": "[![](https://github.com/kaelzhang/stock-pandas/actions/workflows/python.yml/badge.svg)](https://github.com/kaelzhang/stock-pandas/actions/workflows/python.yml)\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[![Conda version](https://img.shields.io/conda/vn/conda-forge/stock-pandas)](https://anaconda.org/conda-forge/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 automated trading much easier. `stock-pandas` requires Python >= **3.9** 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.9\n\n...\n```\n\nThe default `python:3.9` image already contains g++, so we do not install g++ additionally.\n\n#### Install `stock-pandas`\n\n```sh\npip install stock-pandas\n```\n\nA [conda-forge recipe](https://github.com/conda-forge/stock-pandas-feedstock) is also available, so you can also use\n\n```sh\nconda install -c conda-forge stock-pandas\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 directive_stringify\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### `donchian`, Donchian Channels\n\n```\ndonchian:<period>,<column_upper>,<column_lower>\ndonchian.upper:<period>,<column_upper>\ndonchian.lower:<period>,<column_lower>\n```\n\nGets the Donchian channels\n\n- **period** `int`\n- **column_upper?** `str='high'` The column to calculate highest high values, defaults to `'high'`\n- **column_lower?** `str='low'` The column to calculate lowest low values, defaults to `'low'`\n\n```py\n# Donchian middle channel\nstock['donchian']\nstock['donchian.middle']\n\n# Donchian upper channel, a shortcut for stock['donchian.upper']\nstock['donchian.u']\nstock['donchian.upper']\n\n# Donchian lower channel, which is equivalent to stock['donchian.l']\nstock['donchian.lower']\nstock['donchian.l']\n```\n\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## About Pandas Copy-on-Write (CoW) Mode\n\nSince `1.3.0`, `stock-pandas` starts to support pandas [copy-on-write mode](https://pandas.pydata.org/pandas-docs/stable/user_guide/copy_on_write.html#copy-on-write-cow)\n\nYou could enable pandas copy-on-write mode by using `pd.options.mode.copy_on_write = True`\n\nor using the environment variable:\n\n```sh\nexport STOCK_PANDAS_COW=1\n```\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.12\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",
    "bugtrack_url": null,
    "license": "Copyright (c) 2013 kaelzhang <>, contributors  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
    "summary": "The production-ready subclass of `pandas.DataFrame` to support stock statistics and indicators.",
    "version": "1.4.6",
    "project_urls": {
        "Homepage": "https://github.com/kaelzhang/stock-pandas"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "40aac2e3876314d418c1ab0af5340d788387b7aeeea42aa053377a4e26f99a69",
                "md5": "d3604bd207a46b924a4e344c8468d977",
                "sha256": "8a4e9f4396b6b37d0fd31795e95c525d19359eaf465c3650475e59fafd5d059b"
            },
            "downloads": -1,
            "filename": "stock_pandas-1.4.6-cp39-cp39-macosx_11_0_arm64.whl",
            "has_sig": false,
            "md5_digest": "d3604bd207a46b924a4e344c8468d977",
            "packagetype": "bdist_wheel",
            "python_version": "cp39",
            "requires_python": ">=3.9",
            "size": 262488,
            "upload_time": "2024-12-16T13:40:10",
            "upload_time_iso_8601": "2024-12-16T13:40:10.593991Z",
            "url": "https://files.pythonhosted.org/packages/40/aa/c2e3876314d418c1ab0af5340d788387b7aeeea42aa053377a4e26f99a69/stock_pandas-1.4.6-cp39-cp39-macosx_11_0_arm64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "7ee27d5ba1af07c4941516d313009a6cc61140b850fdbb4d3f3452ce9f82e784",
                "md5": "73409a2b06bfb2aba21e5714ae5d17cd",
                "sha256": "28ca6e3e75e010afb9fa4255e9009b9caf1abd6f13299fb9413d6a7eb18ccb1b"
            },
            "downloads": -1,
            "filename": "stock_pandas-1.4.6.tar.gz",
            "has_sig": false,
            "md5_digest": "73409a2b06bfb2aba21e5714ae5d17cd",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 202700,
            "upload_time": "2024-12-16T13:40:13",
            "upload_time_iso_8601": "2024-12-16T13:40:13.858536Z",
            "url": "https://files.pythonhosted.org/packages/7e/e2/7d5ba1af07c4941516d313009a6cc61140b850fdbb4d3f3452ce9f82e784/stock_pandas-1.4.6.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-12-16 13:40:13",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "kaelzhang",
    "github_project": "stock-pandas",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "stock-pandas"
}
        
Elapsed time: 0.38676s