83 lines
1.7 KiB
Go
83 lines
1.7 KiB
Go
package alpaca
|
|
|
|
import (
|
|
"time"
|
|
|
|
"alpaca-bot/internal/config"
|
|
"alpaca-bot/internal/model"
|
|
|
|
"github.com/alpacahq/alpaca-trade-api-go/v3/alpaca"
|
|
"github.com/alpacahq/alpaca-trade-api-go/v3/marketdata"
|
|
"github.com/shopspring/decimal"
|
|
)
|
|
|
|
type Client struct {
|
|
alpacaClient *alpaca.Client
|
|
mdClient *marketdata.Client
|
|
}
|
|
|
|
// Create new Alpaca client
|
|
func NewClient(cfg config.AlpacaConfig) *Client {
|
|
c := alpaca.NewClient(alpaca.ClientOpts{
|
|
APIKey: cfg.ApiKey,
|
|
APISecret: cfg.ApiSecret,
|
|
BaseURL: cfg.TradeURL,
|
|
})
|
|
|
|
md := marketdata.NewClient(marketdata.ClientOpts{
|
|
APIKey: cfg.ApiKey,
|
|
APISecret: cfg.ApiSecret,
|
|
})
|
|
|
|
return &Client{
|
|
alpacaClient: c,
|
|
mdClient: md,
|
|
}
|
|
}
|
|
|
|
// Fetch historical bars
|
|
func (c *Client) GetHistoricalBars(symbol string, timeframe string, start, end time.Time) ([]model.Bar, error) {
|
|
req := marketdata.GetBarsRequest{
|
|
TimeFrame: marketdata.OneHour, // e.g. "1Day", "1Min"
|
|
Start: start,
|
|
End: end,
|
|
}
|
|
|
|
resp, err := c.mdClient.GetBars(symbol, req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
bars := []model.Bar{}
|
|
for _, b := range resp {
|
|
bars = append(bars, model.Bar{
|
|
Symbol: symbol,
|
|
Time: b.Timestamp,
|
|
Open: b.Open,
|
|
High: b.High,
|
|
Low: b.Low,
|
|
Close: b.Close,
|
|
// Volume: b.Volume,
|
|
})
|
|
}
|
|
|
|
return bars, nil
|
|
}
|
|
|
|
// Example: submit an order
|
|
func (c *Client) SubmitOrder(symbol string, qty *decimal.Decimal, side alpaca.Side, orderType alpaca.OrderType, timeInForce alpaca.TimeInForce) (*alpaca.Order, error) {
|
|
orderReq := alpaca.PlaceOrderRequest{
|
|
Symbol: symbol,
|
|
Qty: qty,
|
|
Side: side,
|
|
Type: orderType,
|
|
TimeInForce: timeInForce,
|
|
}
|
|
|
|
order, err := c.alpacaClient.PlaceOrder(orderReq)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return order, nil
|
|
}
|