# RIT API Client
[](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[](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"
}