Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions DEVELOPMENT_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,22 @@ main
- All models have proper type hints
- 100% test coverage

#### 1.2 Trade Data Support
#### 1.2 Trade Data Support
**Branch**: `feature/trade-data-api`
**Priority**: 🔴 Critical
**Estimated Time**: 2 days
**Actual Time**: < 1 day
**Completed**: 2025-01-14

**Tasks**:
- [ ] Create `stock/trades.py` module
- [ ] Implement `get_trades()` method with pagination
- [ ] Implement `get_latest_trade()` method
- [ ] Implement `get_trades_multi()` for multiple symbols
- [ ] Create `TradeModel` dataclass
- [ ] Add feed parameter support (iex, sip, otc)
- [ ] Add comprehensive tests (10+ test cases)
- [ ] Update documentation
- [x] Create `stock/trades.py` module
- [x] Implement `get_trades()` method with pagination
- [x] Implement `get_latest_trade()` method
- [x] Implement `get_trades_multi()` for multiple symbols
- [x] Create `TradeModel` dataclass
- [x] Add feed parameter support (iex, sip, otc)
- [x] Add comprehensive tests (12 unit tests, 10 integration tests)
- [x] Update documentation

**Acceptance Criteria**:
- Can retrieve historical trades with proper pagination
Expand Down Expand Up @@ -283,11 +285,11 @@ main

## 📈 Progress Tracking

### Overall Progress: 🟦 10% Complete
### Overall Progress: 🟦 20% Complete

| Phase | Status | Progress | Estimated Completion |
|-------|--------|----------|---------------------|
| Phase 1: Critical Features | 🟦 In Progress | 33% | Week 3 |
| Phase 1: Critical Features | 🟦 In Progress | 67% | Week 3 |
| Phase 2: Important Enhancements | ⬜ Not Started | 0% | Week 5 |
| Phase 3: Performance & Quality | ⬜ Not Started | 0% | Week 7 |
| Phase 4: Advanced Features | ⬜ Not Started | 0% | Week 10 |
Expand Down
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,52 @@ all_actions = api.trading.corporate_actions.get_announcements(
)
```

### Trade Data

```python
# Get historical trades for a symbol
trades_response = api.stock.trades.get_trades(
symbol="AAPL",
start="2024-01-15T09:30:00Z",
end="2024-01-15T10:00:00Z",
limit=100
)

for trade in trades_response.trades:
print(f"Trade: {trade.size} shares @ ${trade.price} on {trade.exchange}")

# Get latest trade for a symbol
latest_trade = api.stock.trades.get_latest_trade("MSFT")
print(f"Latest MSFT trade: ${latest_trade.price} x {latest_trade.size}")

# Get trades for multiple symbols
multi_trades = api.stock.trades.get_trades_multi(
symbols=["AAPL", "MSFT", "GOOGL"],
start="2024-01-15T09:30:00Z",
end="2024-01-15T10:00:00Z",
limit=10
)

for symbol, trades_data in multi_trades.items():
print(f"{symbol}: {len(trades_data.trades)} trades")

# Get all trades with automatic pagination
all_trades = api.stock.trades.get_all_trades(
symbol="SPY",
start="2024-01-15T09:30:00Z",
end="2024-01-15T09:35:00Z"
)
print(f"Total SPY trades: {len(all_trades)}")

# Use different data feeds (requires subscription)
sip_trades = api.stock.trades.get_trades(
symbol="AAPL",
start="2024-01-15T09:30:00Z",
end="2024-01-15T10:00:00Z",
feed="sip" # or "iex", "otc"
)
```

### Advanced Order Types

```python
Expand Down
77 changes: 77 additions & 0 deletions src/py_alpaca_api/models/trade_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
from dataclasses import dataclass
from typing import Any


@dataclass
class TradeModel:
"""Model for individual stock trade data."""

timestamp: str # RFC-3339 format timestamp
symbol: str
exchange: str
price: float
size: int
conditions: list[str] | None
id: int
tape: str


def trade_class_from_dict(
data: dict[str, Any], symbol: str | None = None
) -> TradeModel:
"""Create TradeModel from API response dictionary.

Args:
data: Dictionary containing trade data from API
symbol: Optional symbol to use if not in data

Returns:
TradeModel instance
"""
return TradeModel(
timestamp=data.get("t", ""),
symbol=data.get("symbol", symbol or ""),
exchange=data.get("x", ""),
price=float(data.get("p", 0.0)),
size=int(data.get("s", 0)),
conditions=data.get("c", []),
id=int(data.get("i", 0)),
tape=data.get("z", ""),
)


@dataclass
class LatestTradeModel:
"""Model for latest trade data with symbol."""

trade: TradeModel
symbol: str


@dataclass
class TradesResponse:
"""Response model for trades endpoint with pagination."""

trades: list[TradeModel]
symbol: str
next_page_token: str | None = None


def extract_trades_data(data: dict[str, Any]) -> dict[str, Any]:
"""Extract and transform trades data from API response.

Args:
data: Raw API response data

Returns:
Transformed dictionary ready for model creation
"""
# Handle both single trade and multiple trades response formats
if "trades" in data:
# Multiple trades response
return data
if "trade" in data:
# Single latest trade response
return {"trades": [data["trade"]], "symbol": data.get("symbol", "")}
# Direct trade data
return {"trades": [data], "symbol": data.get("symbol", "")}
9 changes: 2 additions & 7 deletions src/py_alpaca_api/stock/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from py_alpaca_api.stock.latest_quote import LatestQuote
from py_alpaca_api.stock.predictor import Predictor
from py_alpaca_api.stock.screener import Screener
from py_alpaca_api.stock.trades import Trades
from py_alpaca_api.trading.market import Market


Expand All @@ -25,13 +26,6 @@ def __init__(
headers=headers, base_url=base_url, data_url=data_url, market=market
)

self._initialize_components(
headers=headers,
base_url=base_url,
data_url=data_url,
market=market,
)

def _initialize_components(
self,
headers: dict[str, str],
Expand All @@ -46,3 +40,4 @@ def _initialize_components(
)
self.predictor = Predictor(history=self.history, screener=self.screener)
self.latest_quote = LatestQuote(headers=headers)
self.trades = Trades(headers=headers)
Loading
Loading