ritpy


Nameritpy JSON
Version 0.1.1 PyPI version JSON
download
home_pageNone
SummaryPython wrapper for the Rotman Interactive Trader (RIT) REST API
upload_time2025-10-26 15:19:29
maintainerNone
docs_urlNone
authorEdoardo Cocciò
requires_python>=3.10
licenseNone
keywords algorithmic-trading api finance rit rotman trading
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # RIT API Client

[![Python Version](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)

A comprehensive Python wrapper for the Rotman Interactive Trader (RIT) REST API with built-in error handling, rate limiting, and pandas DataFrame support.

## Features

- **Clean API**: Intuitive methods for all RIT endpoints
- **DataFrame Support**: Automatic conversion of API responses to pandas DataFrames
- **Error Handling**: Robust exception handling for all error scenarios
- **Rate Limiting**: Automatic retry logic for rate-limited requests
- **Type Safety**: Type hints throughout for better IDE support
- **Case Flexibility**: Graceful handling of endpoints not available in specific cases
- **Full Coverage**: All endpoints from RIT API specification implemented

## Installation

### From Source (Development)

```bash
# Clone repository
git clone https://github.com/Dadd0/RITpy.git

# Install package in development mode
uv pip install -e .
```

### From PyPI

```bash
# using uv
uv add ritpy

# equivalently, using pip
pip install ritpy
```

### Configuration

1. Create a `.env` file:
   ```bash
   cp .env.example .env
   ```

2. Add your RIT API key:
   ```
   RIT_API_KEY=your_actual_api_key_here
   ```

## Quick Start

```python
from rit_client import RITClient

# Initialize client (automatically loads .env)
client = RITClient()

# Get case information
case_info = client.get_case()
print(f"Case: {case_info['name']}, Status: {case_info['status']}")

# Get all securities as a DataFrame
securities = client.get_securities()
print(securities[['ticker', 'position', 'last', 'bid', 'ask']])

# Get news feed
news = client.get_news(limit=5)
for _, item in news.iterrows():
    print(f"{item['headline']}: {item['body']}")

# Get order book for a security
book = client.get_order_book('CRZY')
print("Bids:", book['bid'])
print("Asks:", book['ask'])
```

## API Reference

### Case Information

```python
# Get case details
case = client.get_case()

# Check if case is active
if client.is_case_active():
    print("Case is running!")
```

### Trader Information

```python
# Get trader info
trader = client.get_trader()
print(f"NLV: ${trader['nlv']:,.2f}")

# Quick NLV check
nlv = client.get_nlv()
```

### Securities

```python
# Get all securities
securities = client.get_securities()

# Get specific security
security = client.get_security('CRZY')

# Get order book
book = client.get_order_book('CRZY', limit=10)

# Get price history (OHLC)
history = client.get_security_history('CRZY', limit=100)

# Get time & sales
tas = client.get_time_and_sales('CRZY', limit=50)
```

### News

```python
# Get latest news
news = client.get_news(limit=10)

# Get news after specific ID
news = client.get_news(after=150)

# Get single most recent news item
latest = client.get_latest_news()
```

### Orders

**Note**: Order endpoints may not be available in all cases (e.g., Commodities case).

```python
# Get open orders
orders = client.get_open_orders()

# Submit a market order (with error handling)
try:
    order = client.submit_order(
        ticker='CRZY',
        order_type='MARKET',
        quantity=100,
        action='BUY'
    )
except EndpointNotAvailableException:
    print("Orders not available in this case")

# Submit a limit order
order = client.submit_order(
    ticker='CRZY',
    order_type='LIMIT',
    quantity=100,
    action='SELL',
    price=15.50
)

# Cancel order
client.cancel_order(order_id=123)

# Cancel all orders
cancelled = client.cancel_all_orders()

# Cancel by ticker
cancelled = client.cancel_orders_by_ticker('CRZY')
```

### Assets (Commodities Cases)

```python
# Get available assets
assets = client.get_assets()

# Get asset history
history = client.get_asset_history(ticker='CONTAINER')

# Lease an asset
lease = client.lease_asset('CONTAINER')

# Use a leased asset (e.g., refinery)
result = client.use_leased_asset(
    lease_id=1,
    from_tickers=['CRUDE'],
    quantities=[100]
)

# Get active leases
leases = client.get_leases()

# Cancel a lease
client.cancel_lease(lease_id=1)
```

### Trading Limits

```python
# Get trading limits
limits = client.get_limits()
print(limits[['name', 'gross', 'net', 'gross_limit', 'net_limit']])
```

### Tenders

```python
# Get active tenders
tenders = client.get_tenders()

# Accept a tender
client.accept_tender(tender_id=5, price=10.50)

# Decline a tender
client.decline_tender(tender_id=5)
```

### Utility Methods

```python
# Get complete market snapshot
snapshot = client.get_market_snapshot()
# Returns: {'case', 'trader', 'securities', 'limits', 'news', 'orders'}

print(snapshot['securities'])
print(snapshot['news'])
```

## Error Handling

The library provides specific exceptions for different error scenarios:

```python
from rit_client import RITClient
from rit_exceptions import (
    RateLimitException,
    AuthenticationException,
    EndpointNotAvailableException,
    OrderException,
    InvalidParameterException
)

client = RITClient()

try:
    order = client.submit_order(
        ticker='CRZY',
        order_type='LIMIT',
        quantity=100,
        action='BUY',
        price=15.0
    )
except EndpointNotAvailableException:
    print("Orders not available in this case (e.g., Commodities)")
except OrderException as e:
    print(f"Order failed: {e}")
except RateLimitException as e:
    print(f"Rate limited, wait {e.wait_time} seconds")
except AuthenticationException:
    print("Check your API key")
```

## Real-Time Data Streaming

```python
import time

client = RITClient()
last_news_id = 0

while client.is_case_active():
    # Get case info
    case = client.get_case()
    print(f"Tick: {case['tick']}")

    # Check for new news
    news = client.get_news(after=last_news_id, limit=10)
    for _, item in news.iterrows():
        if item['news_id'] > last_news_id:
            print(f"NEWS: {item['headline']}")
            last_news_id = item['news_id']

    # Get current securities data
    securities = client.get_securities()

    # Your trading logic here...

    time.sleep(0.5)  # Avoid rate limiting
```

## Data Analysis Example

```python
import pandas as pd

client = RITClient()

# Download historical data
all_history = {}
securities = client.get_securities()

for ticker in securities['ticker']:
    history = client.get_security_history(ticker, limit=100)
    all_history[ticker] = history

# Analyze and save
for ticker, df in all_history.items():
    df.to_csv(f'data/{ticker}_history.csv', index=False)

    # Calculate statistics
    avg_price = df['close'].mean()
    volatility = df['close'].std()
    print(f"{ticker}: Avg={avg_price:.2f}, Vol={volatility:.2f}")
```

## Configuration

All configuration is done via environment variables in `.env`:

```bash
# Required
RIT_API_KEY=your_api_key_here

# Optional (with defaults)
RIT_BASE_URL=http://localhost:9999/v1
RIT_MAX_RETRIES=3
RIT_RETRY_DELAY=0.5
RIT_TIMEOUT=10
```

You can also pass configuration directly:

```python
client = RITClient(
    api_key='your_key',
    base_url='http://localhost:9999/v1',
    max_retries=5,
    timeout=15
)
```

## Rate Limiting

The client automatically handles rate limiting:
- Retries requests when rate limited
- Uses `Retry-After` header from API
- Configurable max retries and delays
- Raises `RateLimitException` if max retries exceeded

## Case Compatibility

Different RIT cases support different endpoints:

| Endpoint | Commodities | Options | Algorithm | Liquidity |
|----------|-------------|---------|-----------|-----------|
| Securities | ✅ | ✅ | ✅ | ✅ |
| Orders (POST) | ❌ | ✅ | ✅ | ✅ |
| Assets | ✅ | ❌ | ❌ | ❌ |
| Leases | ✅ | ❌ | ❌ | ❌ |
| Tenders | ✅* | ❌ | ❌ | ❌ |

*Depends on specific case configuration

The library gracefully handles unavailable endpoints with `EndpointNotAvailableException`.

## Examples

See `example_usage.py` for comprehensive examples:
```bash
python example_usage.py
```

## Module Structure

```
COM/
├── rit_client.py          # Main client class
├── rit_exceptions.py      # Custom exceptions
├── config.py              # Configuration management
├── example_usage.py       # Usage examples
├── .env.example           # Environment template
├── pyproject.toml         # Dependencies
└── README.md             # This file
```

## Troubleshooting

### API Key Issues
```python
# Check if API key is loaded
from config import Config
Config.validate()  # Raises error if key missing
```

### Connection Issues
- Ensure RIT Client is running
- Check that API is enabled in RIT Client (green API icon)
- Verify base URL matches RIT Client port

### Rate Limiting
- Add `time.sleep()` between requests in loops
- Increase `RIT_RETRY_DELAY` in `.env`
- Reduce polling frequency

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "ritpy",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "algorithmic-trading, api, finance, rit, rotman, trading",
    "author": "Edoardo Cocci\u00f2",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/12/40/2557487540dc6a143b4eae9a449db7561d3b7a4bce369c2a9eb9ef97fd38/ritpy-0.1.1.tar.gz",
    "platform": null,
    "description": "# RIT API Client\n\n[![Python Version](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)\n\nA comprehensive Python wrapper for the Rotman Interactive Trader (RIT) REST API with built-in error handling, rate limiting, and pandas DataFrame support.\n\n## Features\n\n- **Clean API**: Intuitive methods for all RIT endpoints\n- **DataFrame Support**: Automatic conversion of API responses to pandas DataFrames\n- **Error Handling**: Robust exception handling for all error scenarios\n- **Rate Limiting**: Automatic retry logic for rate-limited requests\n- **Type Safety**: Type hints throughout for better IDE support\n- **Case Flexibility**: Graceful handling of endpoints not available in specific cases\n- **Full Coverage**: All endpoints from RIT API specification implemented\n\n## Installation\n\n### From Source (Development)\n\n```bash\n# Clone repository\ngit clone https://github.com/Dadd0/RITpy.git\n\n# Install package in development mode\nuv pip install -e .\n```\n\n### From PyPI\n\n```bash\n# using uv\nuv add ritpy\n\n# equivalently, using pip\npip install ritpy\n```\n\n### Configuration\n\n1. Create a `.env` file:\n   ```bash\n   cp .env.example .env\n   ```\n\n2. Add your RIT API key:\n   ```\n   RIT_API_KEY=your_actual_api_key_here\n   ```\n\n## Quick Start\n\n```python\nfrom rit_client import RITClient\n\n# Initialize client (automatically loads .env)\nclient = RITClient()\n\n# Get case information\ncase_info = client.get_case()\nprint(f\"Case: {case_info['name']}, Status: {case_info['status']}\")\n\n# Get all securities as a DataFrame\nsecurities = client.get_securities()\nprint(securities[['ticker', 'position', 'last', 'bid', 'ask']])\n\n# Get news feed\nnews = client.get_news(limit=5)\nfor _, item in news.iterrows():\n    print(f\"{item['headline']}: {item['body']}\")\n\n# Get order book for a security\nbook = client.get_order_book('CRZY')\nprint(\"Bids:\", book['bid'])\nprint(\"Asks:\", book['ask'])\n```\n\n## API Reference\n\n### Case Information\n\n```python\n# Get case details\ncase = client.get_case()\n\n# Check if case is active\nif client.is_case_active():\n    print(\"Case is running!\")\n```\n\n### Trader Information\n\n```python\n# Get trader info\ntrader = client.get_trader()\nprint(f\"NLV: ${trader['nlv']:,.2f}\")\n\n# Quick NLV check\nnlv = client.get_nlv()\n```\n\n### Securities\n\n```python\n# Get all securities\nsecurities = client.get_securities()\n\n# Get specific security\nsecurity = client.get_security('CRZY')\n\n# Get order book\nbook = client.get_order_book('CRZY', limit=10)\n\n# Get price history (OHLC)\nhistory = client.get_security_history('CRZY', limit=100)\n\n# Get time & sales\ntas = client.get_time_and_sales('CRZY', limit=50)\n```\n\n### News\n\n```python\n# Get latest news\nnews = client.get_news(limit=10)\n\n# Get news after specific ID\nnews = client.get_news(after=150)\n\n# Get single most recent news item\nlatest = client.get_latest_news()\n```\n\n### Orders\n\n**Note**: Order endpoints may not be available in all cases (e.g., Commodities case).\n\n```python\n# Get open orders\norders = client.get_open_orders()\n\n# Submit a market order (with error handling)\ntry:\n    order = client.submit_order(\n        ticker='CRZY',\n        order_type='MARKET',\n        quantity=100,\n        action='BUY'\n    )\nexcept EndpointNotAvailableException:\n    print(\"Orders not available in this case\")\n\n# Submit a limit order\norder = client.submit_order(\n    ticker='CRZY',\n    order_type='LIMIT',\n    quantity=100,\n    action='SELL',\n    price=15.50\n)\n\n# Cancel order\nclient.cancel_order(order_id=123)\n\n# Cancel all orders\ncancelled = client.cancel_all_orders()\n\n# Cancel by ticker\ncancelled = client.cancel_orders_by_ticker('CRZY')\n```\n\n### Assets (Commodities Cases)\n\n```python\n# Get available assets\nassets = client.get_assets()\n\n# Get asset history\nhistory = client.get_asset_history(ticker='CONTAINER')\n\n# Lease an asset\nlease = client.lease_asset('CONTAINER')\n\n# Use a leased asset (e.g., refinery)\nresult = client.use_leased_asset(\n    lease_id=1,\n    from_tickers=['CRUDE'],\n    quantities=[100]\n)\n\n# Get active leases\nleases = client.get_leases()\n\n# Cancel a lease\nclient.cancel_lease(lease_id=1)\n```\n\n### Trading Limits\n\n```python\n# Get trading limits\nlimits = client.get_limits()\nprint(limits[['name', 'gross', 'net', 'gross_limit', 'net_limit']])\n```\n\n### Tenders\n\n```python\n# Get active tenders\ntenders = client.get_tenders()\n\n# Accept a tender\nclient.accept_tender(tender_id=5, price=10.50)\n\n# Decline a tender\nclient.decline_tender(tender_id=5)\n```\n\n### Utility Methods\n\n```python\n# Get complete market snapshot\nsnapshot = client.get_market_snapshot()\n# Returns: {'case', 'trader', 'securities', 'limits', 'news', 'orders'}\n\nprint(snapshot['securities'])\nprint(snapshot['news'])\n```\n\n## Error Handling\n\nThe library provides specific exceptions for different error scenarios:\n\n```python\nfrom rit_client import RITClient\nfrom rit_exceptions import (\n    RateLimitException,\n    AuthenticationException,\n    EndpointNotAvailableException,\n    OrderException,\n    InvalidParameterException\n)\n\nclient = RITClient()\n\ntry:\n    order = client.submit_order(\n        ticker='CRZY',\n        order_type='LIMIT',\n        quantity=100,\n        action='BUY',\n        price=15.0\n    )\nexcept EndpointNotAvailableException:\n    print(\"Orders not available in this case (e.g., Commodities)\")\nexcept OrderException as e:\n    print(f\"Order failed: {e}\")\nexcept RateLimitException as e:\n    print(f\"Rate limited, wait {e.wait_time} seconds\")\nexcept AuthenticationException:\n    print(\"Check your API key\")\n```\n\n## Real-Time Data Streaming\n\n```python\nimport time\n\nclient = RITClient()\nlast_news_id = 0\n\nwhile client.is_case_active():\n    # Get case info\n    case = client.get_case()\n    print(f\"Tick: {case['tick']}\")\n\n    # Check for new news\n    news = client.get_news(after=last_news_id, limit=10)\n    for _, item in news.iterrows():\n        if item['news_id'] > last_news_id:\n            print(f\"NEWS: {item['headline']}\")\n            last_news_id = item['news_id']\n\n    # Get current securities data\n    securities = client.get_securities()\n\n    # Your trading logic here...\n\n    time.sleep(0.5)  # Avoid rate limiting\n```\n\n## Data Analysis Example\n\n```python\nimport pandas as pd\n\nclient = RITClient()\n\n# Download historical data\nall_history = {}\nsecurities = client.get_securities()\n\nfor ticker in securities['ticker']:\n    history = client.get_security_history(ticker, limit=100)\n    all_history[ticker] = history\n\n# Analyze and save\nfor ticker, df in all_history.items():\n    df.to_csv(f'data/{ticker}_history.csv', index=False)\n\n    # Calculate statistics\n    avg_price = df['close'].mean()\n    volatility = df['close'].std()\n    print(f\"{ticker}: Avg={avg_price:.2f}, Vol={volatility:.2f}\")\n```\n\n## Configuration\n\nAll configuration is done via environment variables in `.env`:\n\n```bash\n# Required\nRIT_API_KEY=your_api_key_here\n\n# Optional (with defaults)\nRIT_BASE_URL=http://localhost:9999/v1\nRIT_MAX_RETRIES=3\nRIT_RETRY_DELAY=0.5\nRIT_TIMEOUT=10\n```\n\nYou can also pass configuration directly:\n\n```python\nclient = RITClient(\n    api_key='your_key',\n    base_url='http://localhost:9999/v1',\n    max_retries=5,\n    timeout=15\n)\n```\n\n## Rate Limiting\n\nThe client automatically handles rate limiting:\n- Retries requests when rate limited\n- Uses `Retry-After` header from API\n- Configurable max retries and delays\n- Raises `RateLimitException` if max retries exceeded\n\n## Case Compatibility\n\nDifferent RIT cases support different endpoints:\n\n| Endpoint | Commodities | Options | Algorithm | Liquidity |\n|----------|-------------|---------|-----------|-----------|\n| Securities | \u2705 | \u2705 | \u2705 | \u2705 |\n| Orders (POST) | \u274c | \u2705 | \u2705 | \u2705 |\n| Assets | \u2705 | \u274c | \u274c | \u274c |\n| Leases | \u2705 | \u274c | \u274c | \u274c |\n| Tenders | \u2705* | \u274c | \u274c | \u274c |\n\n*Depends on specific case configuration\n\nThe library gracefully handles unavailable endpoints with `EndpointNotAvailableException`.\n\n## Examples\n\nSee `example_usage.py` for comprehensive examples:\n```bash\npython example_usage.py\n```\n\n## Module Structure\n\n```\nCOM/\n\u251c\u2500\u2500 rit_client.py          # Main client class\n\u251c\u2500\u2500 rit_exceptions.py      # Custom exceptions\n\u251c\u2500\u2500 config.py              # Configuration management\n\u251c\u2500\u2500 example_usage.py       # Usage examples\n\u251c\u2500\u2500 .env.example           # Environment template\n\u251c\u2500\u2500 pyproject.toml         # Dependencies\n\u2514\u2500\u2500 README.md             # This file\n```\n\n## Troubleshooting\n\n### API Key Issues\n```python\n# Check if API key is loaded\nfrom config import Config\nConfig.validate()  # Raises error if key missing\n```\n\n### Connection Issues\n- Ensure RIT Client is running\n- Check that API is enabled in RIT Client (green API icon)\n- Verify base URL matches RIT Client port\n\n### Rate Limiting\n- Add `time.sleep()` between requests in loops\n- Increase `RIT_RETRY_DELAY` in `.env`\n- Reduce polling frequency\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Python wrapper for the Rotman Interactive Trader (RIT) REST API",
    "version": "0.1.1",
    "project_urls": null,
    "split_keywords": [
        "algorithmic-trading",
        " api",
        " finance",
        " rit",
        " rotman",
        " trading"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "e287123b924cd673c186e31b748bf9fec61d78d47518aeebcaa0c033c80d7bde",
                "md5": "40a68195793a7d7392134ca12d50497b",
                "sha256": "3f6894e941af099224409b1fe646f52e7ad632c4c58aade2050050dfc5e7925f"
            },
            "downloads": -1,
            "filename": "ritpy-0.1.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "40a68195793a7d7392134ca12d50497b",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 12261,
            "upload_time": "2025-10-26T15:19:28",
            "upload_time_iso_8601": "2025-10-26T15:19:28.982933Z",
            "url": "https://files.pythonhosted.org/packages/e2/87/123b924cd673c186e31b748bf9fec61d78d47518aeebcaa0c033c80d7bde/ritpy-0.1.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "12402557487540dc6a143b4eae9a449db7561d3b7a4bce369c2a9eb9ef97fd38",
                "md5": "1f81a5d8f92002fe2b93ca021d64d128",
                "sha256": "38a53898acb4cf8cb3bce1d0f4a7aa9eeda704134e69ef761b72e994a33b3ee4"
            },
            "downloads": -1,
            "filename": "ritpy-0.1.1.tar.gz",
            "has_sig": false,
            "md5_digest": "1f81a5d8f92002fe2b93ca021d64d128",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 10409,
            "upload_time": "2025-10-26T15:19:29",
            "upload_time_iso_8601": "2025-10-26T15:19:29.888711Z",
            "url": "https://files.pythonhosted.org/packages/12/40/2557487540dc6a143b4eae9a449db7561d3b7a4bce369c2a9eb9ef97fd38/ritpy-0.1.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-26 15:19:29",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "ritpy"
}
        
Elapsed time: 1.91317s