package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"time"
)
const (
key = "your-key-id"
secret = "your-secret"
host = "https://api.splashsports.com"
)
func sign(secret, timestamp, method, path string, body []byte) string {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(timestamp + method + path))
mac.Write(body)
return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}
func requestWithRetry(method, path string, body []byte, maxAttempts int) (*http.Response, error) {
for attempt := 1; ; attempt++ {
req, err := http.NewRequest(method, host+path, bytes.NewReader(body))
if err != nil {
return nil, err
}
timestamp := strconv.FormatInt(time.Now().UnixMilli(), 10) // signed afresh on every attempt
if len(body) > 0 {
req.Header.Set("Content-Type", "application/json")
}
req.Header.Set("SPLASH-ACCESS-KEY", key)
req.Header.Set("SPLASH-ACCESS-TIMESTAMP", timestamp)
req.Header.Set("SPLASH-ACCESS-SIGNATURE", sign(secret, timestamp, method, path, body))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err // no response: check the order by request_id before resending
}
if resp.StatusCode != http.StatusTooManyRequests || attempt >= maxAttempts {
return resp, nil
}
resp.Body.Close()
// Retry-After when it is a number of seconds; otherwise back off 1 second.
retryAfter, err := strconv.Atoi(resp.Header.Get("Retry-After"))
if err != nil || retryAfter < 0 {
retryAfter = 1
}
jitter := time.Duration(time.Now().UnixNano()%250) * time.Millisecond
time.Sleep(time.Duration(retryAfter*attempt)*time.Second + jitter)
}
}
func main() {
body, err := json.Marshal(map[string]any{
"market_id": "pm_6ae1e3c09e1d4c7a2b5f80e3d6a9c412",
"side": "yes",
"quantity": 10,
"price": 0.59,
"time_in_force": "FOK",
"request_id": "3f1c2a9e-5b7d-4e0a-9c1d-8a6b2e4f7d10",
})
if err != nil {
panic(err)
}
resp, err := requestWithRetry("POST", "/predictions-service/api/trading/orders", body, 5)
if err != nil {
panic(err)
}
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(resp.StatusCode, string(out))
}