96 lines
2.3 KiB
Go
96 lines
2.3 KiB
Go
package etoro
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
const instrumentsURL = "https://api.etoro.com/metadata/instruments"
|
|
|
|
// InstrumentTypeID connus sur eToro
|
|
const (
|
|
TypeStock = 5
|
|
TypeETF = 10
|
|
TypeCrypto = 12
|
|
TypeIndex = 21
|
|
TypeCFD = 6
|
|
)
|
|
|
|
type Client struct {
|
|
http *http.Client
|
|
}
|
|
|
|
type Instrument struct {
|
|
InstrumentID int `json:"InstrumentID"`
|
|
InstrumentDisplayName string `json:"InstrumentDisplayName"`
|
|
SymbolFull string `json:"SymbolFull"`
|
|
InstrumentTypeID int `json:"InstrumentTypeID"`
|
|
IsActive bool `json:"IsActive"`
|
|
StockIndustryID int `json:"StockIndustryID"`
|
|
StockExchangeID int `json:"StockExchangeID"`
|
|
}
|
|
|
|
func New() *Client {
|
|
return &Client{
|
|
http: &http.Client{Timeout: 30 * time.Second},
|
|
}
|
|
}
|
|
|
|
// FetchStocks retourne tous les instruments de type Stock actifs sur eToro.
|
|
func (c *Client) FetchStocks() ([]Instrument, error) {
|
|
all, err := c.fetchAll()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var stocks []Instrument
|
|
for _, inst := range all {
|
|
if inst.IsActive && inst.InstrumentTypeID == TypeStock {
|
|
stocks = append(stocks, inst)
|
|
}
|
|
}
|
|
return stocks, nil
|
|
}
|
|
|
|
// FetchAll retourne tous les instruments (stocks + ETFs + crypto + indices).
|
|
func (c *Client) FetchAll() ([]Instrument, error) {
|
|
return c.fetchAll()
|
|
}
|
|
|
|
func (c *Client) fetchAll() ([]Instrument, error) {
|
|
req, err := http.NewRequest("GET", instrumentsURL, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Headers qui imitent le client web eToro
|
|
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
|
|
req.Header.Set("accounttype", "Demo")
|
|
req.Header.Set("ApplicationIdentifier", "ReToro")
|
|
req.Header.Set("Version", "1.211.0")
|
|
req.Header.Set("Accept", "application/json")
|
|
|
|
resp, err := c.http.Do(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("etoro: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != 200 {
|
|
return nil, fmt.Errorf("etoro: HTTP %d", resp.StatusCode)
|
|
}
|
|
|
|
var instruments []Instrument
|
|
if err := json.NewDecoder(resp.Body).Decode(&instruments); err != nil {
|
|
return nil, fmt.Errorf("etoro: parse error: %w", err)
|
|
}
|
|
|
|
if len(instruments) == 0 {
|
|
return nil, fmt.Errorf("etoro: empty response — l'API a peut-être changé")
|
|
}
|
|
|
|
return instruments, nil
|
|
}
|