mirror of
https://github.com/luxfi/broker.git
synced 2026-11-03 06:52:49 +00:00
Security fixes: - Fix auth bypass: empty API key now returns 401 (unless BROKER_DEV_MODE=true) - Fix risk engine recording $0 for all orders (now calculates qty*price) - Fix hardcoded compliance fields in CreateAccount (pass-through from request) P0 Trading Core: - ReplaceOrder (PATCH), CancelAllOrders, GetPosition, ClosePosition, CloseAllPositions - ListOrdersFiltered with status/limit/after/until/direction/nested params - Extended CreateOrderRequest: trailing stops, bracket orders, extended hours P1-P5 Complete API via composable interfaces: - AccountManager: UpdateAccount, CloseAccount, GetAccountActivities - DocumentManager: Upload, List, Get, Download documents - JournalManager: Create, List, Get, Delete, Batch, ReverseBatch journals - TransferExtended: CancelTransfer, DeleteACH, recipient bank CRUD - CryptoDataProvider: GetCryptoBars/Quotes/Trades/Snapshots - EventStreamer: SSE streaming for trade/account/transfer/journal events - PortfolioAnalyzer: GetPortfolioHistory - WatchlistManager: Full CRUD with asset management Architecture: 8 optional capability interfaces on single Provider abstraction. Providers implement what they support; router detects via type assertion. Market data fixes: - Crypto symbols now route to /v1beta3/crypto/us/ (not /v2/stocks/) - GetBars pagination via next_page_token loop
60 lines
1.4 KiB
Go
60 lines
1.4 KiB
Go
package alpaca
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"github.com/luxfi/broker/pkg/types"
|
|
)
|
|
|
|
// --- PortfolioAnalyzer implementation ---
|
|
|
|
func (p *Provider) GetPortfolioHistory(ctx context.Context, accountID string, params *types.HistoryParams) (*types.PortfolioHistory, error) {
|
|
path := "/v1/trading/accounts/" + accountID + "/account/portfolio/history"
|
|
sep := "?"
|
|
if params != nil {
|
|
if params.Period != "" {
|
|
path += sep + "period=" + params.Period
|
|
sep = "&"
|
|
}
|
|
if params.Timeframe != "" {
|
|
path += sep + "timeframe=" + params.Timeframe
|
|
sep = "&"
|
|
}
|
|
if params.DateEnd != "" {
|
|
path += sep + "date_end=" + params.DateEnd
|
|
sep = "&"
|
|
}
|
|
if params.ExtendedHours {
|
|
path += sep + "extended_hours=true"
|
|
}
|
|
}
|
|
|
|
data, _, err := p.do(ctx, http.MethodGet, path, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var raw struct {
|
|
Timestamp []int64 `json:"timestamp"`
|
|
Equity []float64 `json:"equity"`
|
|
ProfitLoss []float64 `json:"profit_loss"`
|
|
ProfitLossPct []float64 `json:"profit_loss_pct"`
|
|
BaseValue float64 `json:"base_value"`
|
|
Timeframe string `json:"timeframe"`
|
|
}
|
|
if err := json.Unmarshal(data, &raw); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &types.PortfolioHistory{
|
|
Timestamp: raw.Timestamp,
|
|
Equity: raw.Equity,
|
|
ProfitLoss: raw.ProfitLoss,
|
|
ProfitLossPct: raw.ProfitLossPct,
|
|
BaseValue: raw.BaseValue,
|
|
Timeframe: raw.Timeframe,
|
|
}, nil
|
|
}
|