# OpenStoxlify 📈

[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/michaelahli/openstoxlify)
[![Python Version](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)

A lightweight Python library for algorithmic trading and market analysis with professional-grade visualizations.

---

## ✨ Key Features

- **Multi-source data**: Fetch from Yahoo Finance, Binance, and more
- **Context-based API**: Clean, fluent interface for strategy development
- **Strategy engine**: Record and visualize trading signals
- **Professional charts**: OHLC candles, indicators, and strategy markers
- **Flexible outputs**: Interactive plots and JSON for programmatic use

---

## 🚀 Quick Start

```python
from openstoxlify.context import Context
from openstoxlify.draw import Canvas
from openstoxlify.models.enum import ActionType, DefaultProvider, Period, PlotType
from openstoxlify.models.series import ActionSeries, FloatSeries
from openstoxlify.providers.stoxlify.provider import Provider

# 1. Initialize provider and context
provider = Provider(DefaultProvider.YFinance)
ctx = Context(provider, "AAPL", Period.DAILY)

# 2. Get market data
quotes = ctx.quotes()

# 3. Plot closing prices
for quote in quotes:
    ctx.plot("Close", PlotType.LINE, FloatSeries(quote.timestamp, quote.close))

# 4. Add trading signals
ctx.signal(ActionSeries(quotes[0].timestamp, ActionType.LONG, 1.0))

# 5. Visualize
canvas = Canvas(ctx)
canvas.draw()
```

---

## 📦 Installation

### Basic Installation

```bash
pip install openstoxlify
```

### For Development

```bash
git clone https://github.com/michaelahli/openstoxlify.git
cd openstoxlify
make clean setup
source .venv/bin/activate  # or `venv/bin/activate`
python examples/getting_started.py
```

### Requirements

| Package    | Minimum Version | Notes                           |
| ---------- | --------------- | ------------------------------- |
| Python     | 3.8+            |                                 |
| grpcio     | 1.50+           | For data provider communication |
| matplotlib | 3.5+            | Required for visualization      |
| protobuf   | 4.0+            | For protocol buffers            |

### Troubleshooting

1. **Missing Dependencies**:

   ```bash
   pip install --upgrade grpcio matplotlib protobuf
   ```

2. **Permission Issues** (Linux/Mac):

   ```bash
   pip install --user openstoxlify
   ```

3. **Conda Users**:

   ```bash
   conda install -c conda-forge grpcio matplotlib
   pip install openstoxlify
   ```

---

## 📊 Core Components

### 1. Context - The Trading Context Manager

The `Context` class is the heart of OpenStoxlify. It manages your market data, plots, and trading signals in one place.

```python
from openstoxlify.context import Context
from openstoxlify.providers.stoxlify.provider import Provider
from openstoxlify.models.enum import DefaultProvider, Period

# Initialize provider
provider = Provider(DefaultProvider.YFinance)

# Create trading context
ctx = Context(
    provider=provider,
    symbol="BTC-USD",
    period=Period.DAILY
)
```

**Context Methods**:

| Method                  | Description                       | Returns         |
| ----------------------- | --------------------------------- | --------------- |
| `quotes()`              | Get market data (cached)          | `List[Quote]`   |
| `plot(label, type, data, screen_index)` | Add plot data | `None`          |
| `signal(action_series)` | Record trading signal             | `None`          |
| `authenticate(token)`   | Authenticate with provider        | `None`          |
| `execute()`             | Execute latest trading signal     | `None`          |
| `plots()`               | Get all plot data                 | `Dict`          |
| `signals()`             | Get all trading signals           | `List`          |

---

### 2. Providers - Data Sources

**Supported Providers**:

```python
from openstoxlify.models.enum import DefaultProvider

# Available providers
DefaultProvider.YFinance  # Yahoo Finance
DefaultProvider.Binance   # Binance (crypto)
```

**Available Timeframes**:

| Period          | Interval | Description        |
| --------------- | -------- | ------------------ |
| `Period.MINUTELY`   | 1m       | 1-minute candles   |
| `Period.QUINTLY`    | 5m       | 5-minute candles   |
| `Period.HALFHOURLY` | 30m      | 30-minute candles  |
| `Period.HOURLY`     | 60m      | 1-hour candles     |
| `Period.DAILY`      | 1d       | Daily candles      |
| `Period.WEEKLY`     | 1w       | Weekly candles     |
| `Period.MONTHLY`    | 1mo      | Monthly candles    |

**Example**:

```python
from openstoxlify.providers.stoxlify.provider import Provider
from openstoxlify.models.enum import DefaultProvider

provider = Provider(DefaultProvider.Binance)
ctx = Context(provider, "BTCUSDT", Period.HOURLY)
quotes = ctx.quotes()
```

---

### 3. Plotting - Visualize Indicators

Plot technical indicators alongside market data:

```python
from openstoxlify.models.enum import PlotType
from openstoxlify.models.series import FloatSeries

# Plot a single data point
ctx.plot(
    label="SMA 20",              # Indicator name
    plot_type=PlotType.LINE,     # Plot style
    data=FloatSeries(
        timestamp=quote.timestamp,
        value=sma_value
    ),
    screen_index=0               # Main chart (0) or subplot (1, 2, ...)
)
```

**Plot Types**:

| Type                | Description              | Use Case                     |
| ------------------- | ------------------------ | ---------------------------- |
| `PlotType.LINE`     | Continuous line          | Moving averages, price lines |
| `PlotType.HISTOGRAM`| Vertical bars            | Volume, MACD histogram       |
| `PlotType.AREA`     | Filled area under curve  | Bollinger Bands, clouds      |

**Multi-Screen Layouts**:

```python
# Main chart (screen 0)
ctx.plot("Price", PlotType.LINE, FloatSeries(ts, price), screen_index=0)
ctx.plot("SMA 20", PlotType.LINE, FloatSeries(ts, sma20), screen_index=0)

# MACD subplot (screen 1)
ctx.plot("MACD", PlotType.HISTOGRAM, FloatSeries(ts, macd), screen_index=1)

# RSI subplot (screen 2)
ctx.plot("RSI", PlotType.LINE, FloatSeries(ts, rsi), screen_index=2)
```

---

### 4. Trading Signals

Record buy/sell decisions:

```python
from openstoxlify.models.enum import ActionType
from openstoxlify.models.series import ActionSeries

# Record a LONG (buy) signal
ctx.signal(ActionSeries(
    timestamp=quote.timestamp,
    action=ActionType.LONG,
    amount=1.5  # Position size
))

# Record a SHORT (sell) signal
ctx.signal(ActionSeries(
    timestamp=quote.timestamp,
    action=ActionType.SHORT,
    amount=2.0
))

# Record a HOLD (no action)
ctx.signal(ActionSeries(
    timestamp=quote.timestamp,
    action=ActionType.HOLD,
    amount=0.0  # Amount is automatically set to 0 for HOLD
))
```

**Action Types**:

| Type                | Description           | Visual Marker    |
| ------------------- | --------------------- | ---------------- |
| `ActionType.LONG`   | Buy/Bullish position  | ▲ Blue arrow     |
| `ActionType.SHORT`  | Sell/Bearish position | ▼ Purple arrow   |
| `ActionType.HOLD`   | No action             | (not displayed)  |

---

### 5. Canvas - Render Charts

The `Canvas` class generates professional financial charts:

```python
from openstoxlify.draw import Canvas

# Create canvas from context
canvas = Canvas(ctx)

# Draw with default settings
canvas.draw()

# Draw with custom styling
canvas.draw(
    show_legend=True,
    figsize=(16, 9),
    title="My Trading Strategy",
    candle_linewidth=1.5,
    marker_size=10
)
```

---

## 🎨 Visualization with `draw()`

### Basic Usage

```python
from openstoxlify.context import Context
from openstoxlify.draw import Canvas
from openstoxlify.providers.stoxlify.provider import Provider

provider = Provider(DefaultProvider.YFinance)
ctx = Context(provider, "AAPL", Period.DAILY)

# Add your plots and signals...

canvas = Canvas(ctx)
canvas.draw()  # Displays interactive matplotlib chart
```

### Full Customization Example

```python
canvas.draw(
    show_legend=True,             # Toggle legend visibility
    figsize=(16, 9),              # Larger figure size
    offset_multiplier=0.03,       # Adjust trade marker positions
    rotation=45,                  # X-axis label rotation
    ha='right',                   # Horizontal alignment
    title="Custom Strategy Backtest",
    xlabel="Trading Days",
    ylabel="Price (USD)",
    candle_linewidth=0.8,         # Wick thickness
    candle_body_width=3,          # Body thickness
    marker_size=10,               # Trade signal markers
    annotation_fontsize=8,        # Trade annotation text
    histogram_alpha=0.7,          # Histogram transparency
    area_alpha=0.4,               # Area plot transparency
    line_width=2.5                # Trend line thickness
)
```

### Chart Features

| Element          | Description                         | Example Visual    |
| ---------------- | ----------------------------------- | ----------------- |
| **Candlesticks** | Green/red based on price direction  | 🟩🟥                |
| **Signals**      | Annotated markers for trades        | ▲ LONG<br>▼ SHORT |
| **Indicators**   | Lines, histograms, and filled areas | ━━━━━             |

### Example Output

![Sample Chart](public/images/ma_chart.png)

### Key Parameters

| Parameter             | Type  | Default                      | Description                       |
| --------------------- | ----- | ---------------------------- | --------------------------------- |
| `show_legend`         | bool  | True                         | Show/hide chart legend            |
| `figsize`             | tuple | (12, 6)                      | Figure dimensions (width, height) |
| `offset_multiplier`   | float | 0.05                         | Trade marker offset from price    |
| `rotation`            | int   | 30                           | X-axis label rotation angle       |
| `ha`                  | str   | 'right'                      | X-axis label horizontal alignment |
| `title`               | str   | "Market Data Visualizations" | Chart title                       |
| `xlabel`              | str   | "Date"                       | X-axis label                      |
| `ylabel`              | str   | "Price"                      | Y-axis label                      |
| `candle_linewidth`    | float | 1                            | Candlestick wick line width       |
| `candle_body_width`   | float | 4                            | Candlestick body line width       |
| `marker_size`         | int   | 8                            | Trade marker size                 |
| `annotation_fontsize` | int   | 9                            | Trade annotation font size        |
| `histogram_alpha`     | float | 0.6                          | Histogram bar transparency        |
| `area_alpha`          | float | 0.3                          | Area plot transparency            |
| `line_width`          | float | 2                            | Line plot width                   |

---

## 📚 Complete Examples

### 1. Simple Trading Strategy (from `getting_started.py`)

```python
from statistics import median
from openstoxlify.context import Context
from openstoxlify.draw import Canvas
from openstoxlify.models.enum import ActionType, DefaultProvider, Period, PlotType
from openstoxlify.models.series import ActionSeries, FloatSeries
from openstoxlify.providers.stoxlify.provider import Provider

# Setup
provider = Provider(DefaultProvider.YFinance)
ctx = Context(provider, "BTC-USD", Period.DAILY)

# Get market data
quotes = ctx.quotes()

# Calculate median price
prices = [quote.close for quote in quotes]
median_value = median(prices)

# Find extremes
lowest = min(quotes, key=lambda q: q.close)
highest = max(quotes, key=lambda q: q.close)

# Plot median line
for quote in quotes:
    ctx.plot("Median", PlotType.LINE, FloatSeries(quote.timestamp, median_value))

# Add signals at extremes
ctx.signal(ActionSeries(lowest.timestamp, ActionType.LONG, 1))
ctx.signal(ActionSeries(highest.timestamp, ActionType.SHORT, 1))

# Visualize
canvas = Canvas(ctx)
canvas.draw()
```

### 2. Moving Average Crossover

```python
from openstoxlify.context import Context
from openstoxlify.draw import Canvas
from openstoxlify.models.enum import ActionType, DefaultProvider, Period, PlotType
from openstoxlify.models.series import ActionSeries, FloatSeries
from openstoxlify.providers.stoxlify.provider import Provider

def calculate_sma(prices, period):
    """Simple Moving Average"""
    return [
        sum(prices[i:i+period]) / period 
        for i in range(len(prices) - period + 1)
    ]

# Setup
provider = Provider(DefaultProvider.YFinance)
ctx = Context(provider, "AAPL", Period.DAILY)
quotes = ctx.quotes()

# Calculate indicators
closes = [q.close for q in quotes]
sma_20 = calculate_sma(closes, 20)
sma_50 = calculate_sma(closes, 50)

# Plot price and moving averages
for i, quote in enumerate(quotes):
    ctx.plot("Price", PlotType.LINE, FloatSeries(quote.timestamp, quote.close))
    
    if i >= 19:  # SMA 20 starts at index 19
        sma_20_idx = i - 19
        ctx.plot("SMA 20", PlotType.LINE, FloatSeries(quote.timestamp, sma_20[sma_20_idx]))
    
    if i >= 49:  # SMA 50 starts at index 49
        sma_50_idx = i - 49
        ctx.plot("SMA 50", PlotType.LINE, FloatSeries(quote.timestamp, sma_50[sma_50_idx]))
        
        # Generate signals on crossovers
        if sma_50_idx > 0:
            prev_fast = sma_20[sma_20_idx - 1]
            prev_slow = sma_50[sma_50_idx - 1]
            curr_fast = sma_20[sma_20_idx]
            curr_slow = sma_50[sma_50_idx]
            
            # Bullish crossover
            if prev_fast <= prev_slow and curr_fast > curr_slow:
                ctx.signal(ActionSeries(quote.timestamp, ActionType.LONG, 1.0))
            
            # Bearish crossover
            elif prev_fast >= prev_slow and curr_fast < curr_slow:
                ctx.signal(ActionSeries(quote.timestamp, ActionType.SHORT, 1.0))

# Visualize
canvas = Canvas(ctx)
canvas.draw(title="SMA Crossover Strategy", figsize=(14, 8))
```

### 3. Multi-Indicator Strategy (from `subplots.py`)

See the full example in `examples/subplots.py` which demonstrates:

- Multiple screen layouts
- MACD histogram on subplot
- Stochastic oscillator on separate panel
- Combined signal generation from multiple indicators

---

## 🔄 Migration Guide (Old API → New API)

### Before (Old API)

```python
from openstoxlify.fetch import fetch
from openstoxlify.plotter import plot
from openstoxlify.strategy import act
from openstoxlify.draw import draw
from openstoxlify.models import Period, Provider, PlotType, ActionType

# Old way
market_data = fetch("BTCUSDT", Provider.Binance, Period.MINUTELY)
quotes = market_data.quotes

for quote in quotes:
    plot(PlotType.LINE, "Median", quote.timestamp, median_value)

act(ActionType.LONG, lowest.timestamp, 1)
draw()
```

### After (New API)

```python
from openstoxlify.context import Context
from openstoxlify.draw import Canvas
from openstoxlify.models.enum import DefaultProvider, Period, PlotType, ActionType
from openstoxlify.models.series import FloatSeries, ActionSeries
from openstoxlify.providers.stoxlify.provider import Provider

# New way - Context-based
provider = Provider(DefaultProvider.Binance)
ctx = Context(provider, "BTCUSDT", Period.MINUTELY)

quotes = ctx.quotes()

for quote in quotes:
    ctx.plot("Median", PlotType.LINE, FloatSeries(quote.timestamp, median_value))

ctx.signal(ActionSeries(lowest.timestamp, ActionType.LONG, 1))

canvas = Canvas(ctx)
canvas.draw()
```

### Key Changes

| Old API                          | New API                                    |
| -------------------------------- | ------------------------------------------ |
| `fetch(symbol, provider, period)` | `Context(provider, symbol, period).quotes()` |
| `plot(type, label, ts, value)`   | `ctx.plot(label, type, FloatSeries(ts, value))` |
| `act(action, timestamp, amount)` | `ctx.signal(ActionSeries(ts, action, amount))` |
| `draw()`                         | `Canvas(ctx).draw()`                       |
| Import from `models`             | Import from `models.enum`, `models.series` |

---

## 📖 API Reference

### Data Structures

#### Quote

```python
@dataclass
class Quote:
    timestamp: datetime  # Time of measurement
    high: float          # Period high price
    low: float           # Period low price
    open: float          # Opening price
    close: float         # Closing price
    volume: float        # Trading volume
```

#### FloatSeries

```python
@dataclass
class FloatSeries:
    timestamp: datetime  # Data point time
    value: float         # Indicator value
```

#### ActionSeries

```python
@dataclass
class ActionSeries:
    timestamp: datetime  # Signal time
    action: ActionType   # LONG, SHORT, or HOLD
    amount: float        # Position size
```

---

## 🔐 Authentication & Execution

For live trading with supported providers:

```python
# Authenticate
ctx.authenticate("your-api-token")

# Execute the latest signal
ctx.execute()  # Only executes if authenticated
```

**Note**: `execute()` will only run if:

1. Context is authenticated
2. There's a signal at the latest timestamp
3. The signal is not `ActionType.HOLD`

---

## 💡 Best Practices

1. **Cache quotes**: Context automatically caches `quotes()` calls per symbol
2. **Use screen_index**: Separate indicators into different panels for clarity
3. **Consistent timestamps**: All timestamps are timezone-aware UTC
4. **Plot incrementally**: Call `ctx.plot()` in loops for time-series data
5. **Signal at decision points**: Only call `ctx.signal()` when strategy makes a decision

---

## 🧪 Testing

Run the test suite:

```bash
# Run all tests
make test

# Run with coverage
pytest tests/ --cov=openstoxlify --cov-report=html

# Run specific test file
pytest tests/test_context.py -v
```

---

## 🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to the branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request

---

## 📄 License

MIT © 2026 OpenStoxlify

---

## 🔗 Links

- [Documentation](https://github.com/michaelahli/openstoxlify/wiki)
- [Examples](https://github.com/michaelahli/openstoxlify/tree/main/examples)
- [Issue Tracker](https://github.com/michaelahli/openstoxlify/issues)
- [DeepWiki](https://deepwiki.com/michaelahli/openstoxlify)

---

## ⭐ Support

If you find this library helpful, please consider giving it a star on GitHub!
