Full Code of gregyjames/Panther for AI

main 9050091feb27 cached
10 files
16.6 KB
5.0k tokens
10 symbols
1 requests
Download .txt
Repository: gregyjames/Panther
Branch: main
Commit: 9050091feb27
Files: 10
Total size: 16.6 KB

Directory structure:
gitextract_gksj4ub1/

├── .github/
│   └── workflows/
│       ├── CI.yml
│       └── rust.yml
├── .gitignore
├── Cargo.toml
├── LICENSE
├── README.md
├── pyproject.toml
├── speed_tests/
│   ├── ema.py
│   └── sma.py
└── src/
    └── lib.rs

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/CI.yml
================================================
name: CI

on:
  push:
    branches:
      - main
    tags:
      - "*"
  pull_request:

jobs:
  macos:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-python@v2
        with:
          python-version: 3.9
          architecture: x64
      - name: Install Rust toolchain
        uses: actions-rs/toolchain@v1
        with:
          toolchain: nightly
          profile: minimal
          default: true
      - name: Build wheels - x86_64
        uses: messense/maturin-action@v1
        with:
          target: x86_64
          args: --release --out dist
      - name: Install built wheel - x86_64
        run: |
          pip install numpy
          pip install ZenithTA --no-deps --no-index --find-links dist --force-reinstall
          python -c 'import ZenithTA'
      - name: Build wheels - universal2
        uses: messense/maturin-action@v1
        with:
          args: --release --universal2 --out dist --no-sdist
      - name: Install built wheel - universal2
        run: |
          pip install ZenithTA --no-deps --no-index --find-links dist --force-reinstall
          python -c 'import ZenithTA'
      - name: Upload wheels
        uses: actions/upload-artifact@v2
        with:
          name: wheels
          path: dist

  windows:
    runs-on: windows-latest
    strategy:
      matrix:
        target: [x86]
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-python@v2
        with:
          python-version: 3.9
          architecture: ${{ matrix.target }}
      - name: Install Rust toolchain
        uses: actions-rs/toolchain@v1
        with:
          toolchain: nightly
          profile: minimal
          default: true
      - name: Build wheels
        uses: messense/maturin-action@v1
        with:
          target: ${{ matrix.target }}
          args: --release --out dist --no-sdist
      - name: Install built wheel
        run: |
          pip install numpy
          pip install ZenithTA --no-deps --no-index --find-links dist --force-reinstall
          python -c 'import ZenithTA'
      - name: Upload wheels
        uses: actions/upload-artifact@v2
        with:
          name: wheels
          path: dist

  linux:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        target: [x86_64, i686]
    steps:
    - uses: actions/checkout@v2
    - uses: actions/setup-python@v2
      with:
        python-version: 3.9
        architecture: x64
    - name: Build wheels
      uses: messense/maturin-action@v1
      with:
        rust-toolchain: nightly
        target: ${{ matrix.target }}
        manylinux: auto
        args: --release --out dist --no-sdist
    - name: Install built wheel
      if: matrix.target == 'x86_64'
      run: |
        pip install numpy
        pip install ZenithTA --no-deps --no-index --find-links dist --force-reinstall
        python -c 'import ZenithTA'
    - name: Upload wheels
      uses: actions/upload-artifact@v2
      with:
        name: wheels
        path: dist

  linux-cross:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        target: [aarch64, armv7, s390x, ppc64le]
    steps:
    - uses: actions/checkout@v2
    - uses: actions/setup-python@v2
      with:
        python-version: 3.9
    - name: Build wheels
      uses: messense/maturin-action@v1
      with:
        rust-toolchain: nightly
        target: ${{ matrix.target }}
        manylinux: auto
        args: --release --out dist --no-sdist
    - uses: uraimo/run-on-arch-action@v2.0.5
      name: Install built wheel
      if: matrix.target == 'aarch64'
      with:
        arch: ${{ matrix.target }}
        distro: ubuntu20.04
        githubToken: ${{ github.token }}
        install: |
          apt-get update
          apt-get install -y --no-install-recommends python3 python3-pip
          pip3 install -U pip numpy
        run: |
          pip3 install ZenithTA --no-deps --no-index --find-links dist/ --force-reinstall
          python3 -c 'import ZenithTA'
    - name: Upload wheels
      uses: actions/upload-artifact@v2
      with:
        name: wheels
        path: dist

  release:
    name: Release
    runs-on: ubuntu-latest
    if: "startsWith(github.ref, 'refs/tags/')"
    needs: [ macos, windows, linux, linux-cross ]
    steps:
      - uses: actions/download-artifact@v3
        with:
          name: wheels
      - name: Publish to PyPi
        env:
          MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
        uses: PyO3/maturin-action@v1
        with:
          command: upload
          args: --skip-existing *

================================================
FILE: .github/workflows/rust.yml
================================================
name: Rust

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

env:
  CARGO_TERM_COLOR: always

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: Cargo Cache
      uses: actions/cache@v1
      with:
        path: ~/.cargo
        key: ${{ runner.os }}-cargo-${{ hashFiles('Cargo.toml') }}
        restore-keys: |
          ${{ runner.os }}-cargo-${{ hashFiles('Cargo.toml') }}
          ${{ runner.os }}-cargo

    - name: Cargo Target Cache
      uses: actions/cache@v1
      with:
        path: target
        key: ${{ runner.os }}-cargo-target-${{ hashFiles('Cargo.toml') }}
        restore-keys: |
          ${{ runner.os }}-cargo-target-${{ hashFiles('Cargo.toml') }}
          ${{ runner.os }}-cargo-target

    - name: Build
      run: cargo build --release --verbose
    - name: Run tests
      run: cargo test --verbose


================================================
FILE: .gitignore
================================================
# Generated by Cargo
# will have compiled files and executables
/target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk


# Added by cargo
#
# already existing elements were commented out

/target
#Cargo.lock

# Add for maturin
dist/


================================================
FILE: Cargo.toml
================================================
[package]
name = "ZenithTA"
version = "1.0.0"
edition = "2021"

[lib]
name = "ZenithTA"
crate-type = ["cdylib"]

[dependencies]
pyo3 = { version = "0.15.1", features = ["abi3-py36", "extension-module"] }
numpy = "0.15"


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2022 Greg

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.


================================================
FILE: README.md
================================================
[![Rust](https://img.shields.io/github/actions/workflow/status/gregyjames/zenithta/rust.yml?style=for-the-badge)](https://github.com/gregyjames/ZenithTA/actions/workflows/rust.yml)
[![PyPI](https://img.shields.io/pypi/v/zenithta?color=%230s0&style=for-the-badge)](https://pypi.org/project/zenithta/)
[![License](https://img.shields.io/github/license/gregyjames/zenithta?color=%230sd&style=for-the-badge)](https://github.com/gregyjames/ZenithTA/blob/main/LICENSE)
[![Count](https://img.shields.io/tokei/lines/github/gregyjames/zenithta?color=%230fs&style=for-the-badge)](https://github.com/gregyjames/ZenithTA/)



# ZenithTA
#### Formerly Panther
A efficient, high-performance python technical analysis library written in Rust using PyO3 and rust-numpy. 

## Indicators
- ATR
- CMF
- SMA
- EMA
- RSI
- MACD
- ROC

## How to install
`pip3 install zenithta`

## How to build (Windows)
- Run `cargo build --release` from the main directory.
- Get the generated dll from the target/release directory.
- Rename extension from .dll to .pyd.
- Place .pyd file in the same folder as script. 
- Put `from panther import *` in python script.
 
## Speed
On average, I found the Panther calculations of these indicators to be about 9x or 900% faster than the industry standard way of calculating these indicators using Pandas. Don't believe me? Install the library and run the tests in the speed_tests directory to see it for yourself :)

## License
MIT License

Copyright (c) 2022 Greg James

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.


================================================
FILE: pyproject.toml
================================================
[build-system]
requires = ["maturin>=0.12,<0.13"]
build-backend = "maturin"

[project]
name = "ZenithTA"
dependencies = [
    "numpy"
]


================================================
FILE: speed_tests/ema.py
================================================
import pandas_datareader as pdr
import pandas as pd
from ZenithTA import *
from timeit import default_timer as timer
from datetime import timedelta

data = pdr.get_data_yahoo('NVDA')

print("Timing ZenithTA:")
start = timer()
a = data['Close'].tolist()
j = ema(a,4,2.0)
end = timer()
print(j[0:10:1])
print(timedelta(seconds=end-start))

print("Timing Pandas:")
start = timer()
data['4dayEWM'] = data['Close'].ewm(span=4, adjust=False).mean()
b = data['4dayEWM'].tolist()
print(b[0:10:1])
end = timer()
print(timedelta(seconds=end-start))

================================================
FILE: speed_tests/sma.py
================================================
import pandas_datareader as pdr
import pandas as pd
from ZenithTA import *
from timeit import default_timer as timer
from datetime import timedelta

data = pdr.get_data_yahoo('NVDA')

print("Timing ZenithTA:")
a = data['Close'].tolist()
start = timer()
j = sma(a,5)
end = timer()
print(timedelta(seconds=end-start))

print("Timing Pandas:")
start = timer()
data['SMA(5)'] = data.Close.rolling(5).mean()
end = timer()
b = data['SMA(5)'].tolist()
print(timedelta(seconds=end-start))


================================================
FILE: src/lib.rs
================================================
use pyo3::prelude::*;
use pyo3::wrap_pyfunction;
use numpy::ndarray::prelude::*;

//Helper functions for indicators
fn sma_helper(price_ndarray: &Array1<f32>, period: usize) -> Array1<f32>{
    let length = price_ndarray.len() - period +1;
    let mut result = Array1::<f32>::zeros(length);

    for i in 0..length {
        let slice = price_ndarray.slice(s![i..i+period]);
        result[i] = slice.sum()/(period as f32);
    }
    
    result
}

fn ema_helper(price_ndarray: &Array1<f32>, period: usize) -> Array1<f32>{
    let length = price_ndarray.len() - period +1;
    let mut result = Array1::<f32>::zeros(length);
    result[0] = price_ndarray.slice(s![0..period]).sum();
    for i in 1..length{
        result[i] = result[i-1]+(price_ndarray[i+period-1]-result[i-1])*(2.0/((period as f32)+1.0));
    }
    
    result
}

//Indicator Python function wrappers
#[pyfunction]
fn sma(price: Vec<f32>, period: usize) -> PyResult<Vec<f32>> {
    let price_ndarray = Array::from_vec(price);
    let length = price_ndarray.len() - period +1;
    let mut result = Array1::<f32>::zeros(length);

    for i in 0..length {
        let slice = price_ndarray.slice(s![i..i+period]);
        result[i] = slice.sum()/(period as f32);
    }

    Ok(Array::to_vec(&result))
}

#[pyfunction]
fn ema(price: Vec<f32>, period: usize, smoothing: f32) -> PyResult<Vec<f32>> {
    let price_ndarray = Array::from_vec(price);
    let length = price_ndarray.len();
    let mut result = Array1::<f32>::zeros(length);
    
    let weight = smoothing / (period + 1) as f32;
    result[0] = price_ndarray[0];

    for i in 1..length {
        result[i] = (price_ndarray[i]*weight) + (result[i-1] * (1.0-weight));
    }

    Ok(Array::to_vec(&result))
}

#[pyfunction]
fn rsi(price: Vec<f32>, period: usize) -> PyResult<Vec<f32>>{
    let price_ndarray = Array::from_vec(price);
    let mut change = Array1::<f32>::zeros(price_ndarray.len());
    let mut gain = Array1::<f32>::zeros(price_ndarray.len());
    let mut loss = Array1::<f32>::zeros(price_ndarray.len());
    let mut ag = Array1::<f32>::zeros(price_ndarray.len());
    let mut al = Array1::<f32>::zeros(price_ndarray.len());
    let mut result = Array1::<f32>::zeros(price_ndarray.len());
    for i in 1..price_ndarray.len(){
        change[i] = price_ndarray[i] - price_ndarray[i-1];
        if change[i] == 0.0{
            gain[i] = 0.0;
            loss[i] = 0.0;
        } else if change[i]<0.0{
            gain[i] = 0.0;
            loss[i] = (change[i]).abs();
        }else{
            gain[i] = change[i];
            loss[i] = 0.0;
        }
    }
    ag[period] = gain.slice(s![1..period+1]).sum()/(period as f32);
    al[period] = loss.slice(s![1..period+1]).sum()/(period as f32);
    
    for i in period+1..price_ndarray.len(){
        ag[i] = (ag[i-1]*(period as f32-1.0)+gain[i])/period as f32;
        al[i] = (al[i-1]*(period as f32-1.0)+loss[i])/period as f32;
    }
    for i in period+1..price_ndarray.len(){
        result[i] = 100.0-(100.0/(1.0+ag[i]/al[i]))
    }

    //result.slice(s![period..]).to_owned()
    Ok(Array::to_vec(&(result.slice(s![period..]).to_owned())))
}

#[pyfunction]
fn macd(price: Vec<f32>, period_fast: usize, period_slow: usize, period_signal: usize) -> PyResult<(Vec<f32>,Vec<f32>)>{
    let price_ndarray = Array::from_vec(price);
    let line = ema_helper(&price_ndarray, period_fast).slice(s![period_slow-period_fast..]).to_owned() - ema_helper(&price_ndarray,period_slow);
    let signal = ema_helper(&price_ndarray, period_signal);

    Ok((Array::to_vec(&line), Array::to_vec(&signal)))
}

#[pyfunction]
fn roc(price: Vec<f32>, period: usize) -> PyResult<Vec<f32>> {
    let price_ndarray = Array::from_vec(price);
    let length = price_ndarray.len() - period;
    let mut result = Array1::<f32>::zeros(length);

    for i in period..price_ndarray.len() {
        result[i-period] = ((price_ndarray[i]-price_ndarray[i-period])/price_ndarray[i-period])*100.0;
    }

    Ok(Array::to_vec(&result))
}

#[pyfunction]
fn atr(high: Vec<f32>, low: Vec<f32>, close: Vec<f32>, period: usize) -> PyResult<Vec<f32>> {
    let length = high.len();
    let high_ndarray = Array::from_vec(high);
    let low_ndarray = Array::from_vec(low);
    let close_ndarray = Array::from_vec(close);
    let mut tr  = Array1::<f32>::zeros(length);
    let mut result = Array1::<f32>::zeros(length - period + 1);
    
    tr[0] = high_ndarray[0]-low_ndarray[0];
    for i in 1..high_ndarray.len() {
        let hl = high_ndarray[i] - low_ndarray[i];
        let hpc = (high_ndarray[i] - close_ndarray[i-1]).abs();
        let lpc = (low_ndarray[i] - close_ndarray[i-1]).abs();
        tr[i] = f32::max(f32::max(hl, hpc), lpc);
    }


    result[0] = tr.slice(s![0..period]).sum()/period as f32;

    for i in 1.. length -period+1 {
        result[i] = (result[i-1]*(period as f32-1.0)+tr[i+period-1])/period as f32;
    }
    Ok(Array::to_vec(&result))
}

#[pyfunction]
fn cmf(high: Vec<f32>, low: Vec<f32>, close: Vec<f32>, volume: Vec<f32>, period: usize) -> PyResult<Vec<f32>> {
    let length = high.len();
    let high_ndarray = Array::from_vec(high);
    let low_ndarray = Array::from_vec(low);
    let close_ndarray = Array::from_vec(close);
    let volume_ndarray = Array::from_vec(volume);
    let mut result = Array1::<f32>::zeros(length - period + 1);

    let a = (&close_ndarray)-(&low_ndarray);
    let b = (&high_ndarray)-(&close_ndarray);
    let c = (&high_ndarray)-(&low_ndarray);

    let mfv = ((a-b)/c)*period as f32;
    for i in 0..length-period+1 {
        result[i] =  mfv.slice(s![i..i+period]).sum()/ volume_ndarray.slice(s![i..i+period]).sum();
    }

    Ok(Array::to_vec(&result))
}

#[pymodule]
fn ZenithTA(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(sma, m)?)?;
    m.add_function(wrap_pyfunction!(cmf, m)?)?;
    m.add_function(wrap_pyfunction!(atr, m)?)?;
    m.add_function(wrap_pyfunction!(ema, m)?)?;
    m.add_function(wrap_pyfunction!(rsi, m)?)?;
    m.add_function(wrap_pyfunction!(roc, m)?)?;
    m.add_function(wrap_pyfunction!(macd, m)?)?;
    Ok(())
}

Download .txt
gitextract_gksj4ub1/

├── .github/
│   └── workflows/
│       ├── CI.yml
│       └── rust.yml
├── .gitignore
├── Cargo.toml
├── LICENSE
├── README.md
├── pyproject.toml
├── speed_tests/
│   ├── ema.py
│   └── sma.py
└── src/
    └── lib.rs
Download .txt
SYMBOL INDEX (10 symbols across 1 files)

FILE: src/lib.rs
  function sma_helper (line 6) | fn sma_helper(price_ndarray: &Array1<f32>, period: usize) -> Array1<f32>{
  function ema_helper (line 18) | fn ema_helper(price_ndarray: &Array1<f32>, period: usize) -> Array1<f32>{
  function sma (line 31) | fn sma(price: Vec<f32>, period: usize) -> PyResult<Vec<f32>> {
  function ema (line 45) | fn ema(price: Vec<f32>, period: usize, smoothing: f32) -> PyResult<Vec<f...
  function rsi (line 61) | fn rsi(price: Vec<f32>, period: usize) -> PyResult<Vec<f32>>{
  function macd (line 98) | fn macd(price: Vec<f32>, period_fast: usize, period_slow: usize, period_...
  function roc (line 107) | fn roc(price: Vec<f32>, period: usize) -> PyResult<Vec<f32>> {
  function atr (line 120) | fn atr(high: Vec<f32>, low: Vec<f32>, close: Vec<f32>, period: usize) ->...
  function cmf (line 146) | fn cmf(high: Vec<f32>, low: Vec<f32>, close: Vec<f32>, volume: Vec<f32>,...
  function ZenithTA (line 167) | fn ZenithTA(_py: Python, m: &PyModule) -> PyResult<()> {
Condensed preview — 10 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (18K chars).
[
  {
    "path": ".github/workflows/CI.yml",
    "chars": 4573,
    "preview": "name: CI\n\non:\n  push:\n    branches:\n      - main\n    tags:\n      - \"*\"\n  pull_request:\n\njobs:\n  macos:\n    runs-on: maco"
  },
  {
    "path": ".github/workflows/rust.yml",
    "chars": 902,
    "preview": "name: Rust\n\non:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n\nenv:\n  CARGO_TERM_COLOR: always\n\n"
  },
  {
    "path": ".gitignore",
    "chars": 434,
    "preview": "# Generated by Cargo\n# will have compiled files and executables\n/target/\n\n# Remove Cargo.lock from gitignore if creating"
  },
  {
    "path": "Cargo.toml",
    "chars": 219,
    "preview": "[package]\nname = \"ZenithTA\"\nversion = \"1.0.0\"\nedition = \"2021\"\n\n[lib]\nname = \"ZenithTA\"\ncrate-type = [\"cdylib\"]\n\n[depend"
  },
  {
    "path": "LICENSE",
    "chars": 1061,
    "preview": "MIT License\n\nCopyright (c) 2022 Greg\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof th"
  },
  {
    "path": "README.md",
    "chars": 2505,
    "preview": "[![Rust](https://img.shields.io/github/actions/workflow/status/gregyjames/zenithta/rust.yml?style=for-the-badge)](https:"
  },
  {
    "path": "pyproject.toml",
    "chars": 136,
    "preview": "[build-system]\nrequires = [\"maturin>=0.12,<0.13\"]\nbuild-backend = \"maturin\"\n\n[project]\nname = \"ZenithTA\"\ndependencies = "
  },
  {
    "path": "speed_tests/ema.py",
    "chars": 538,
    "preview": "import pandas_datareader as pdr\nimport pandas as pd\nfrom ZenithTA import *\nfrom timeit import default_timer as timer\nfro"
  },
  {
    "path": "speed_tests/sma.py",
    "chars": 481,
    "preview": "import pandas_datareader as pdr\nimport pandas as pd\nfrom ZenithTA import *\nfrom timeit import default_timer as timer\nfro"
  },
  {
    "path": "src/lib.rs",
    "chars": 6110,
    "preview": "use pyo3::prelude::*;\nuse pyo3::wrap_pyfunction;\nuse numpy::ndarray::prelude::*;\n\n//Helper functions for indicators\nfn s"
  }
]

About this extraction

This page contains the full source code of the gregyjames/Panther GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 10 files (16.6 KB), approximately 5.0k tokens, and a symbol index with 10 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!