mirror of
https://github.com/lukewilson2002/autotrader.git
synced 2025-08-03 05:29:32 +00:00
Added Oanda module
This commit is contained in:
117
oanda/oanda.go
Normal file
117
oanda/oanda.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package oanda
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
auto "github.com/fivemoreminix/autotrader"
|
||||
)
|
||||
|
||||
const (
|
||||
oandaLiveURL = "https://api-fxtrade.oanda.com"
|
||||
oandaPracticeURL = "https://api-fxpractice.oanda.com"
|
||||
TimeLayout = time.RFC3339
|
||||
)
|
||||
|
||||
var _ auto.Broker = (*OandaBroker)(nil) // Compile-time interface check.
|
||||
|
||||
type OandaBroker struct {
|
||||
*auto.SignalManager
|
||||
client *http.Client
|
||||
token string
|
||||
accountID string
|
||||
baseUrl string // Either oandaLiveURL or oandaPracticeURL.
|
||||
}
|
||||
|
||||
func NewOandaBroker(token, accountID string, practice bool) *OandaBroker {
|
||||
var baseUrl string
|
||||
if practice {
|
||||
baseUrl = oandaPracticeURL
|
||||
} else {
|
||||
baseUrl = oandaLiveURL
|
||||
}
|
||||
return &OandaBroker{
|
||||
SignalManager: &auto.SignalManager{},
|
||||
client: &http.Client{},
|
||||
token: token,
|
||||
accountID: accountID,
|
||||
baseUrl: baseUrl,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *OandaBroker) Candles(symbol, frequency string, count int) (*auto.DataFrame, error) {
|
||||
req, err := http.NewRequest("GET", b.baseUrl+"/v3/accounts/"+b.accountID+"/instruments/"+symbol+"/candles", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+b.token)
|
||||
q := req.URL.Query()
|
||||
q.Add("granularity", frequency)
|
||||
q.Add("count", strconv.Itoa(auto.Min(count, 5000))) // API says max is 5000.
|
||||
req.URL.RawQuery = q.Encode()
|
||||
resp, err := b.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var candlestickResponse *CandlestickResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&candlestickResponse); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newDataframe(candlestickResponse)
|
||||
}
|
||||
|
||||
func (b *OandaBroker) MarketOrder(symbol string, units, stopLoss, takeProfit float64) (auto.Order, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (b *OandaBroker) NAV() float64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (b *OandaBroker) PL() float64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (b *OandaBroker) OpenOrders() []auto.Order {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *OandaBroker) OpenPositions() []auto.Position {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *OandaBroker) Orders() []auto.Order {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *OandaBroker) Positions() []auto.Position {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *OandaBroker) fetchAccountUpdates() {
|
||||
}
|
||||
|
||||
func newDataframe(candles *CandlestickResponse) (*auto.DataFrame, error) {
|
||||
if candles == nil {
|
||||
return nil, fmt.Errorf("candles is nil or empty")
|
||||
}
|
||||
data := auto.NewDOHLCVDataFrame()
|
||||
for _, candle := range candles.Candles {
|
||||
if candle.Mid == nil {
|
||||
return nil, fmt.Errorf("mid is nil or empty")
|
||||
}
|
||||
var o, h, l, c float64
|
||||
err := candle.Mid.Parse(&o, &h, &l, &c)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing mid field of a candlestick: %w", err)
|
||||
}
|
||||
data.PushCandle(candle.Time, o, h, l, c, int64(candle.Volume))
|
||||
}
|
||||
return data, nil
|
||||
}
|
Reference in New Issue
Block a user