# Trading Cycle

[![npm version](https://img.shields.io/npm/v/trading-cycle.svg)](https://www.npmjs.com/package/trading-cycle)  [![Build Status](https://github.com/vladtarrow/trading-cycle/actions/workflows/ci.yml/badge.svg)](https://github.com/vladtarrow/trading-cycle/actions)  [![Codecov](https://img.shields.io/codecov/c/github/vladtarrow/trading-cycle.svg?branch=main)](https://codecov.io/gh/vladtarrow/trading-cycle)  [![code style: prettier](https://img.shields.io/badge/code%20style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)

[![bundle size](https://badgen.net/bundlephobia/min/trading-cycle)](https://bundlephobia.com/package/trading-cycle)  [![bundle minzipped size](https://badgen.net/bundlephobia/minzip/trading-cycle)](https://bundlephobia.com/package/trading-cycle)  [![dependencies](https://badgen.net/bundlephobia/dependency-count/trading-cycle)](https://bundlephobia.com/package/trading-cycle)

A lightweight, modular core library designed for backtesting trading strategies in financial markets.

## Installation

Install the full or light version depending on your use case:

```bash
# Full version (with built-in indicators and helpers)
npm install trading-cycle

# Light version (core only)
npm install trading-cycle
```

## Usage

### Full Version

```ts
import {
  Candles,
  PositiveValues,
  NegativeValues,
  Renko,
  TimeRenko,
  TestLogic,
  PositiveTimeLength,
  NegativeTimeLength,
  FakeTrader,
  LogCandle,
  RenkoCounter
} from 'trading-cycle/full';
```

### Light Version

```ts
import { TradingCycle } from 'trading-cycle/light';
```

## Versions

- **Full**: Includes core, built-in indicators, helpers, and utility functions.
- **Light**: Contains only the core functionality — `TradingCycle` class and abstract handler interfaces.

## Built-in Handlers

Trading Cycle ships with a set of predefined handlers you can use out of the box:

```
  Candles,
  PositiveValues,
  NegativeValues,
  Renko,
  TimeRenko,
  TestLogic,
  PositiveTimeLength,
  NegativeTimeLength,
  FakeTrader,
  LogCandle,
  RenkoCounter
```

## Default Preset Configuration

A default preset is provided under `trading-cycle/config`, pre-wiring common handlers with sensible defaults (e.g. Renko bar size of 0.05):

```ts
import defaultPreset from 'trading-cycle/config';
```

This preset includes handlers such as:
- `candles`
- `log-candles`
- `renko-0.05`
- `time-renko`
- `renko-counter`
- `test-logic`
- `fake-trader`

Customize or extend it by supplying your own `HandlerConfig[]` when creating `TradingCycle`.

## Handler Example

Below is a concise description of a custom handler, illustrating how you can extend the core functionality:

1. **Class Declaration**  
   Create a class that extends `AbstractHandler`.
2. **Internal State**  
   Define private fields (e.g., `prev`) to store data between ticks.
3. **Constructor**  
   Call `super(state, config)` to initialize base properties and set up your own fields.
4. **Override `doExecute()`**
   - Access input values via `this.v` and stored state via `this._s`.
   - Implement your logic (e.g., detect when the current close is lower than the previous close).
   - Update internal state (`this.prev = this.v.input;`).
   - Return a result only when the condition is met.

**NegativeValues** handler example (pseudocode):

> Extends `AbstractHandler`, tracks the previous candle in `prev`, and returns the current candle when its close is less than the previous close.

## Example: Backtest from CSV

A quick outline to run a backtest with CSV data:

```ts
import TradingCycle from 'trading-cycle';
import handlers from 'trading-cycle/full';
import defaultPreset from 'trading-cycle/config';

// Initialize the cycle
const cycle = new TradingCycle(handlers, defaultPreset);

// Load your CSV into `ticks: Array<{ o, h, l, c, v }>`
// e.g. via `csv-parse` or any CSV loader

ticks.forEach(tick => cycle.execute(tick));

// Inspect results
console.log(cycle.state);
```

## API Overview

- `new TradingCycle(handlerClasses: Record<string, HandlerConstructor>, preset: HandlerConfig[])` — Create a cycle with provided handlers and configuration presets.
- `execute(tick: any): void` — Run all handlers on a single market tick; results accumulate in `cycle.state`.
- `cycle.state: Record<string, any[]>` — Current output arrays for each handler.

## Design Philosophy

- **Modularity**: Handlers are self-contained units; you can add, remove or customize them without affecting others.
- **Flexibility**: Presets define the pipeline; you control data flow by composing inputs and defaults.
- **Simplicity**: Core abstractions (`TradingCycle`, `AbstractHandler`) remain minimal and clear.

## Continuous Integration

This project uses GitHub Actions for CI and Codecov for coverage reporting.

### Setup

1. **Add Codecov action**: No extra npm packages needed, simply configure the workflow.
2. **Create a secret**: Add `CODECOV_TOKEN` in your repository's *Settings > Secrets*.

### Workflow (`.github/workflows/ci.yml`)

```yaml
name: CI

on:
  push:
    branches: [ main ]
  pull_request:

jobs:
  build-and-test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 18

      - name: Install dependencies
        run: yarn install --frozen-lockfile

      - name: Run tests
        run: yarn test --coverage

      - name: Upload to Codecov
        uses: codecov/codecov-action@v3
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
```

## License

MIT

## Author

[Vladyslav Tarasenko](https://github.com/vladtarrow)

