mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-04 15:10:54 +00:00
cmd/exchange_template, exchanges: Update templates and propogate to exchanges (#1777)
* Added TimeInForce type and updated related files * Linter issue fix and minor coinbasepro type update * Bitrex consts update * added unit test and minor changes in bittrex * Unit tests update * Fix minor linter issues * Update TestStringToTimeInForce unit test * Exchange test template change * A different approach * fix conflict with gateio timeInForce * minor exchange template update * Minor fix to test_files template * Update order tests * Complete updating the order unit tests * Updating exchange wrapper and test template files * update kucoin and deribit wrapper to match the time in force change * minor comment update * fix time-in-force related test errors * linter issue fix * ADD_NEW_EXCHANGE documentation update * time in force constants, functions and unit tests update * shift tif policies to TimeInForce * Update time-in-force, related functions, and unit tests * fix linter issue and time-in-force processing * added a good till crossing tif value * order type fix and fix related tim-in-force entries * update time-in-force unmarshaling and unit test * consistency guideline added * fix time-in-force error in gateio * linter issue fix * update based on review comments * add unit test and fix missing issues * minor fix and added benchmark unit test * change GTT to GTC for limit * fix linter issue * added time-in-force value to place order param * fix minor issues based on review comment and move tif code to separate files * update on exchanges linked to time-in-force * resolve missing review comments * minor linter issues fix * added time-in-force handler and update timeInForce parametered endpoint * minor fixes based on review * nits fix * update based on review * linter fix * rm getTimeInForce func and minor change to time-in-force * minor change * update based on review comments * wrappers and time-in-force calling approach * minor change * update gateio string to timeInForce conversion and unit test * update exchange template * update wrapper template file * policy comments, and template files update * rename all exchange types name to Exchange * update on template files and template generation * templates and generation code and other updates * linter issue fix * added subscriptions and websocket templates * update ADD_NEW_EXCHANGE.md with recent binance functions and implementations * rename template files and update unit tests * minor template and unit test fix * rename templates and fix on unit tests * update on template files and documentation * removed unnecessary tag fix and update templates * fix Add_NEW_EXCHANGE.md doc file * formatting, comments, and error checks update on template files * rename exchange receivers to e and ex for consistency * rename unit test exchange receiver and minor updates * linter issues fix * fix deribit issue and minor style update * fix test issues caused by receiver change * raname local variables exchange declaration variables * update templates comments * update templates and related comments * renamed ex to e * update template comments * toggle WS to false to improve coverage * template comments update * added test coverage to Ws enabled and minor changes --------- Co-authored-by: Samuel Reid <43227667+cranktakular@users.noreply.github.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
@@ -28,22 +29,19 @@ const (
|
||||
type exchange struct {
|
||||
Name string
|
||||
CapitalName string
|
||||
Variable string
|
||||
REST bool
|
||||
WS bool
|
||||
FIX bool
|
||||
}
|
||||
|
||||
var errInvalidExchangeName = errors.New("invalid exchange name")
|
||||
|
||||
func main() {
|
||||
var newExchangeName string
|
||||
var websocketSupport, restSupport, fixSupport bool
|
||||
var websocketSupport, restSupport bool
|
||||
|
||||
flag.StringVar(&newExchangeName, "name", "", "the exchange name")
|
||||
flag.BoolVar(&websocketSupport, "ws", false, "whether the exchange supports websocket")
|
||||
flag.BoolVar(&restSupport, "rest", false, "whether the exchange supports REST")
|
||||
flag.BoolVar(&fixSupport, "fix", false, "whether the exchange supports FIX")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
@@ -62,8 +60,8 @@ func main() {
|
||||
}
|
||||
newExchangeName = strings.ToLower(newExchangeName)
|
||||
|
||||
if !websocketSupport && !restSupport && !fixSupport {
|
||||
log.Println("At least one protocol must be specified (rest/ws or fix)")
|
||||
if !websocketSupport && !restSupport {
|
||||
log.Println("At least one protocol must be specified (rest/ws)")
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
@@ -71,7 +69,6 @@ func main() {
|
||||
fmt.Println("Exchange Name: ", newExchangeName)
|
||||
fmt.Println("Websocket Supported: ", websocketSupport)
|
||||
fmt.Println("REST Supported: ", restSupport)
|
||||
fmt.Println("FIX Supported: ", fixSupport)
|
||||
fmt.Println()
|
||||
fmt.Println("Please check if everything is correct and then type y to continue or n to cancel...")
|
||||
|
||||
@@ -89,7 +86,6 @@ func main() {
|
||||
Name: newExchangeName,
|
||||
REST: restSupport,
|
||||
WS: websocketSupport,
|
||||
FIX: fixSupport,
|
||||
}
|
||||
exchangeDirectory := filepath.Join(targetPath, exch.Name)
|
||||
configTestFile := config.GetConfig()
|
||||
@@ -104,15 +100,6 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("GoCryptoTrader: Exchange templating tool service complete")
|
||||
fmt.Println("When the exchange code implementation has been completed (REST/Websocket/wrappers and tests), please add the exchange to engine/exchange.go")
|
||||
fmt.Println("Add the exchange config settings to config_example.json (it will automatically be added to testdata/configtest.json)")
|
||||
fmt.Println("Increment the available exchanges counter in config/config_test.go")
|
||||
fmt.Println("Add the exchange name to exchanges/support.go")
|
||||
fmt.Println("Ensure go test ./... -race passes")
|
||||
fmt.Println("Open a pull request")
|
||||
fmt.Println("If help is needed, please post a message in Slack.")
|
||||
}
|
||||
|
||||
func checkExchangeName(exchName string) error {
|
||||
@@ -147,7 +134,6 @@ func makeExchange(exchangeDirectory string, configTestFile *config.Config, exch
|
||||
fmt.Printf("Output directory: %s\n", exchangeDirectory)
|
||||
|
||||
exch.CapitalName = cases.Title(language.English).String(exch.Name)
|
||||
exch.Variable = exch.Name[0:2]
|
||||
newExchConfig := &config.Exchange{}
|
||||
newExchConfig.Name = exch.CapitalName
|
||||
newExchConfig.Enabled = true
|
||||
@@ -173,31 +159,38 @@ func makeExchange(exchangeDirectory string, configTestFile *config.Config, exch
|
||||
{
|
||||
Name: "readme",
|
||||
Filename: "README.md",
|
||||
TemplateFile: "readme_file.tmpl",
|
||||
TemplateFile: "readme.tmpl",
|
||||
},
|
||||
{
|
||||
Name: "main",
|
||||
Filename: "main_file.tmpl",
|
||||
FilePostfix: ".go",
|
||||
TemplateFile: "main_file.tmpl",
|
||||
Name: "rest",
|
||||
Filename: "rest.go",
|
||||
TemplateFile: "rest.tmpl",
|
||||
},
|
||||
{
|
||||
Name: "test",
|
||||
Filename: "test_file.tmpl",
|
||||
FilePostfix: "_test.go",
|
||||
TemplateFile: "test_file.tmpl",
|
||||
TemplateFile: "test.tmpl",
|
||||
},
|
||||
{
|
||||
Name: "type",
|
||||
Filename: "type_file.tmpl",
|
||||
FilePostfix: "_types.go",
|
||||
TemplateFile: "type_file.tmpl",
|
||||
Name: "types",
|
||||
Filename: "types.go",
|
||||
TemplateFile: "types.tmpl",
|
||||
},
|
||||
{
|
||||
Name: "wrapper",
|
||||
Filename: "wrapper_file.tmpl",
|
||||
FilePostfix: "_wrapper.go",
|
||||
TemplateFile: "wrapper_file.tmpl",
|
||||
Filename: "wrapper.go",
|
||||
TemplateFile: "wrapper.tmpl",
|
||||
},
|
||||
{
|
||||
Name: "subscriptions",
|
||||
Filename: "subscriptions.go",
|
||||
TemplateFile: "subscriptions.tmpl",
|
||||
},
|
||||
{
|
||||
Name: "websocket",
|
||||
Filename: "websocket.go",
|
||||
TemplateFile: "websocket.tmpl",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -209,6 +202,9 @@ func makeExchange(exchangeDirectory string, configTestFile *config.Config, exch
|
||||
}
|
||||
|
||||
filename := outputFiles[x].Filename
|
||||
if !exch.WS && slices.Contains([]string{"websocket", "subscriptions"}, outputFiles[x].Name) {
|
||||
continue
|
||||
}
|
||||
if outputFiles[x].FilePostfix != "" {
|
||||
filename = exch.Name + outputFiles[x].FilePostfix
|
||||
}
|
||||
|
||||
@@ -5,12 +5,15 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/thrasher-corp/gocryptotrader/common/file"
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
)
|
||||
|
||||
func TestCheckExchangeName(t *testing.T) {
|
||||
tester := []struct {
|
||||
t.Parallel()
|
||||
for _, tt := range []struct {
|
||||
Name string
|
||||
ErrExpected error
|
||||
}{
|
||||
@@ -36,12 +39,16 @@ func TestCheckExchangeName(t *testing.T) {
|
||||
{
|
||||
Name: "testexch",
|
||||
},
|
||||
}
|
||||
|
||||
for x := range tester {
|
||||
if r := checkExchangeName(tester[x].Name); r != tester[x].ErrExpected {
|
||||
t.Errorf("test: %d unexpected result", x)
|
||||
}
|
||||
} {
|
||||
t.Run(tt.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := checkExchangeName(tt.Name)
|
||||
if tt.ErrExpected == nil {
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
assert.Equal(t, tt.ErrExpected, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +63,7 @@ func TestNewExchangeAndSaveConfig(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
exchCfg, err := makeExchange(
|
||||
_, err := makeExchange(
|
||||
testExchangeDir,
|
||||
cfg,
|
||||
&exchange{
|
||||
@@ -65,18 +72,28 @@ func TestNewExchangeAndSaveConfig(t *testing.T) {
|
||||
WS: true,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = os.RemoveAll(testExchangeDir)
|
||||
require.NoErrorf(t, err, "RemoveAll failed: %s, manual deletion of test directory required", err)
|
||||
|
||||
exchCfg, err := makeExchange(
|
||||
testExchangeDir,
|
||||
cfg,
|
||||
&exchange{
|
||||
Name: testExchangeName,
|
||||
REST: true,
|
||||
WS: false,
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
cfgData, err := os.ReadFile(exchangeConfigPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = saveConfig(testExchangeDir, cfg, exchCfg); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err = os.WriteFile(exchangeConfigPath, cfgData, file.DefaultPermissionOctal); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
require.NoError(t, err, "os.ReadFile must not error")
|
||||
|
||||
err = saveConfig(testExchangeDir, cfg, exchCfg)
|
||||
require.NoError(t, err, "saveConfig must not error")
|
||||
|
||||
err = os.WriteFile(exchangeConfigPath, cfgData, file.DefaultPermissionOctal)
|
||||
require.NoError(t, err, "os.WriteFile must not error")
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
{{define "main"}}
|
||||
package {{.Name}}
|
||||
|
||||
import (
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
)
|
||||
|
||||
// {{.CapitalName}} is the overarching type across this package
|
||||
type {{.CapitalName}} struct {
|
||||
exchange.Base
|
||||
}
|
||||
|
||||
const (
|
||||
{{.Name}}APIURL = ""
|
||||
{{.Name}}APIVersion = ""
|
||||
|
||||
// Public endpoints
|
||||
|
||||
// Authenticated endpoints
|
||||
)
|
||||
|
||||
// Start implementing public and private exchange API funcs below
|
||||
|
||||
{{end}}
|
||||
@@ -13,19 +13,10 @@ You can track ideas, planned features and what's in progress on our [GoCryptoTra
|
||||
|
||||
{{if .REST}}+ REST Support {{end}}
|
||||
{{if .WS}}+ Websocket Support {{end}}
|
||||
{{if .FIX}}+ FIX Support {{end}}
|
||||
+ Can be used as a package
|
||||
|
||||
## Notes
|
||||
|
||||
+ Please add notes here with any production issues
|
||||
+ Please provide link to exchange website and API documentation
|
||||
|
||||
## Contributors
|
||||
|
||||
+ Please add your information
|
||||
|
||||
|User|Github|Contribution|
|
||||
|--|--|--|
|
||||
|AliasGoesHere|https://github.com/AliasGoesHere |WHAT-YOU-DID|
|
||||
{{end}}
|
||||
51
cmd/exchange_template/rest.tmpl
Normal file
51
cmd/exchange_template/rest.tmpl
Normal file
@@ -0,0 +1,51 @@
|
||||
{{define "rest"}}
|
||||
package {{.Name}}
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
||||
)
|
||||
|
||||
// Exchange implements exchange.IBotExchange and contains additional specific API methods for interacting with {{.CapitalName}}
|
||||
type Exchange struct {
|
||||
exchange.Base
|
||||
}
|
||||
|
||||
const (
|
||||
apiURL = ""
|
||||
apiVersion = ""
|
||||
|
||||
// Public endpoints
|
||||
|
||||
// Authenticated endpoints
|
||||
)
|
||||
|
||||
// SendHTTPRequest sends an unauthenticated HTTP request
|
||||
func (e *Exchange) SendHTTPRequest(ctx context.Context, path string, result any) error {
|
||||
// This is used to generate the *http.Request, used in conjunction with the
|
||||
// generate functionality below.
|
||||
item := &request.Item{
|
||||
Method: http.MethodGet,
|
||||
Path: path,
|
||||
Result: result,
|
||||
Verbose: e.Verbose,
|
||||
HTTPDebugging: e.HTTPDebugging,
|
||||
HTTPRecording: e.HTTPRecording,
|
||||
}
|
||||
|
||||
// Request function that closes over the above request.Item values, which
|
||||
// executes on every attempt after rate limiting.
|
||||
generate := func() (*request.Item, error) { return item, nil }
|
||||
|
||||
endpoint := request.Unset // Used in conjunction with the rate limiting
|
||||
// system defined in the exchange package to slow down outbound requests
|
||||
// depending on each individual endpoint.
|
||||
return e.SendPayload(ctx, endpoint, generate, request.UnauthenticatedRequest)
|
||||
}
|
||||
|
||||
// Start implementing public and private exchange API funcs below
|
||||
// Private endpoints can be implemented in a separate file with a _private.go suffix for ease of access and simplicity.
|
||||
{{end}}
|
||||
14
cmd/exchange_template/subscriptions.tmpl
Normal file
14
cmd/exchange_template/subscriptions.tmpl
Normal file
@@ -0,0 +1,14 @@
|
||||
{{define "subscriptions"}}
|
||||
package {{.Name}}
|
||||
|
||||
import (
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/subscription"
|
||||
)
|
||||
|
||||
var defaultSubscriptions = subscription.List{
|
||||
{Enabled: true, Asset: asset.All, Channel: subscription.TickerChannel},
|
||||
{Enabled: true, Asset: asset.All, Channel: subscription.OrderbookChannel, Interval: kline.HundredMilliseconds},
|
||||
}
|
||||
{{end}}
|
||||
39
cmd/exchange_template/test.tmpl
Normal file
39
cmd/exchange_template/test.tmpl
Normal file
@@ -0,0 +1,39 @@
|
||||
{{define "test"}}
|
||||
package {{.Name}}
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
testexch "github.com/thrasher-corp/gocryptotrader/internal/testing/exchange"
|
||||
)
|
||||
|
||||
// Please supply your own keys here to do authenticated endpoint testing
|
||||
const (
|
||||
apiKey = ""
|
||||
apiSecret = ""
|
||||
canManipulateRealOrders = false
|
||||
)
|
||||
|
||||
var e *Exchange
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
e = new(Exchange)
|
||||
if err := testexch.Setup(e); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if apiKey != "" && apiSecret != "" {
|
||||
e.API.AuthenticatedSupport = true
|
||||
{{ if .WS }} e.API.AuthenticatedWebsocketSupport = true {{ end }}
|
||||
e.SetCredentials(apiKey, apiSecret, "", "", "", "")
|
||||
{{ if .WS }} e.Websocket.SetCanUseAuthenticatedEndpoints(true) {{ end }}
|
||||
}
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
|
||||
// Implement tests for API endpoints below
|
||||
{{end}}
|
||||
@@ -1,57 +0,0 @@
|
||||
{{define "test"}}
|
||||
package {{.Name}}
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
)
|
||||
|
||||
// Please supply your own keys here to do authenticated endpoint testing
|
||||
const (
|
||||
apiKey = ""
|
||||
apiSecret = ""
|
||||
canManipulateRealOrders = false
|
||||
)
|
||||
|
||||
var {{.Variable}} = &{{.CapitalName}}{}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
{{.Variable}}.SetDefaults()
|
||||
cfg := config.GetConfig()
|
||||
err := cfg.LoadConfig("../../testdata/configtest.json", true)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
exchCfg, err := cfg.GetExchangeConfig("{{.CapitalName}}")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
exchCfg.API.AuthenticatedSupport = true
|
||||
{{ if .WS }} exchCfg.API.AuthenticatedWebsocketSupport = true {{ end }}
|
||||
exchCfg.API.Credentials.Key = apiKey
|
||||
exchCfg.API.Credentials.Secret = apiSecret
|
||||
|
||||
err = {{.Variable}}.Setup(exchCfg)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
// Ensures that this exchange package is compatible with IBotExchange
|
||||
func TestInterface(t *testing.T) {
|
||||
var e exchange.IBotExchange
|
||||
if e = new({{.CapitalName}}); e == nil {
|
||||
t.Fatal("unable to allocate exchange")
|
||||
}
|
||||
}
|
||||
|
||||
// Implement tests for API endpoints below
|
||||
{{end}}
|
||||
@@ -1,3 +0,0 @@
|
||||
{{define "type"}}
|
||||
package {{.Name}}
|
||||
{{end}}
|
||||
8
cmd/exchange_template/types.tmpl
Normal file
8
cmd/exchange_template/types.tmpl
Normal file
@@ -0,0 +1,8 @@
|
||||
{{define "types"}}
|
||||
package {{.Name}}
|
||||
/* For efficiency, a JSON to Golang converter can be used: https://mholt.github.io/json-to-go/
|
||||
However, great care must be taken as to the values which are autogenerated. The JSON converter tool will default to whatever type it detects,
|
||||
but ultimately conversions to a more useful variable type would be better. For example, price and quantity on some exchange API's provide these as strings. Internally,
|
||||
it would be better if they're converted to the more useful float64 var type.
|
||||
*/
|
||||
{{end}}
|
||||
78
cmd/exchange_template/websocket.tmpl
Normal file
78
cmd/exchange_template/websocket.tmpl
Normal file
@@ -0,0 +1,78 @@
|
||||
{{define "websocket"}}
|
||||
package {{.Name}}
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
gws "github.com/gorilla/websocket"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchange/websocket"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/subscription"
|
||||
)
|
||||
|
||||
const (
|
||||
wsAPIURL = ""
|
||||
)
|
||||
|
||||
// WsConnect creates a new websocket connection.
|
||||
func (e *Exchange) WsConnect() error {
|
||||
ctx := context.TODO()
|
||||
if !e.Websocket.IsEnabled() || !e.IsEnabled() {
|
||||
return websocket.ErrWebsocketNotEnabled
|
||||
}
|
||||
dialer := gws.Dialer{
|
||||
HandshakeTimeout: e.Config.HTTPTimeout,
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
}
|
||||
|
||||
if e.Websocket.CanUseAuthenticatedEndpoints() {
|
||||
// Add WebSocket authentication logic here.
|
||||
}
|
||||
|
||||
if err := e.Websocket.Conn.Dial(ctx, &dialer, http.Header{}); err != nil {
|
||||
return fmt.Errorf("%v - Unable to connect to Websocket. Error: %s", e.Name, err)
|
||||
}
|
||||
|
||||
e.Websocket.Wg.Add(1)
|
||||
go e.wsReadData(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Exchange) generateSubscriptions() (subscription.List, error) {
|
||||
return e.Features.Subscriptions.ExpandTemplates(e)
|
||||
}
|
||||
|
||||
// Subscribe sends websocket messages to receive data for a list of channels
|
||||
func (e *Exchange) Subscribe(_ subscription.List) error {
|
||||
// ctx := context.TODO()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unsubscribe sends websocket messages to stop receiving data for a list of channels
|
||||
func (e *Exchange) Unsubscribe(_ subscription.List) error {
|
||||
// ctx := context.TODO()
|
||||
return nil
|
||||
}
|
||||
|
||||
// wsReadData receives and passes on websocket messages for processing
|
||||
func (e *Exchange) wsReadData(ctx context.Context) {
|
||||
defer e.Websocket.Wg.Done()
|
||||
for {
|
||||
resp := e.Websocket.Conn.ReadMessage()
|
||||
if resp.Raw == nil {
|
||||
return
|
||||
}
|
||||
if err := e.wsHandleData(ctx, resp.Raw); err != nil {
|
||||
// e.Websocket.DataHandler <- err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// wsHandleData processes a websocket incoming data.
|
||||
func (e *Exchange) wsHandleData(ctx context.Context, respData []byte) error {
|
||||
// Implement message parsing and handling logic here.
|
||||
return nil
|
||||
}
|
||||
|
||||
{{end}}
|
||||
530
cmd/exchange_template/wrapper.tmpl
Normal file
530
cmd/exchange_template/wrapper.tmpl
Normal file
@@ -0,0 +1,530 @@
|
||||
{{define "wrapper"}}
|
||||
package {{.Name}}
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/common/key"
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchange/websocket"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/deposit"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/fundingrate"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/futures"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/margin"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/protocol"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/trade"
|
||||
"github.com/thrasher-corp/gocryptotrader/log"
|
||||
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
|
||||
)
|
||||
|
||||
// SetDefaults sets the basic defaults for {{.CapitalName}}
|
||||
func (e *Exchange) SetDefaults() {
|
||||
e.Name = "{{.CapitalName}}"
|
||||
e.Enabled = true
|
||||
e.Verbose = true
|
||||
e.API.CredentialsValidator.RequiresKey = true
|
||||
e.API.CredentialsValidator.RequiresSecret = true
|
||||
|
||||
// If using only one pair format for request and configuration, across all supported asset types either SPOT and FUTURES etc. You can use the example below:
|
||||
// Request format denotes what the pair as a string will be, when you send a request to an exchange.
|
||||
requestFmt := ¤cy.PairFormat{/*Set pair request formatting details here for e.g.*/ Uppercase: true, Delimiter: ":"}
|
||||
// Config format denotes how the currency pair should be represented as a string, including the delimiter between base and quote currency,
|
||||
// when saved to the config.json file.
|
||||
configFmt := ¤cy.PairFormat{/*Set pair request formatting details here*/}
|
||||
if err := e.SetGlobalPairsManager(requestFmt, configFmt, /*multiple assets can be set here using the asset package ie asset.Spot*/); err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
|
||||
// If assets require multiple differences in formatting for request and
|
||||
// configuration, another exchange method can be used e.g. futures
|
||||
// contracts require a dash as a delimiter rather than an underscore. You
|
||||
// can use this example below:
|
||||
|
||||
fmt1 := currency.PairStore{
|
||||
AssetEnabled: true,
|
||||
RequestFormat: ¤cy.PairFormat{Uppercase: true},
|
||||
ConfigFormat: ¤cy.PairFormat{Uppercase: true},
|
||||
}
|
||||
|
||||
fmt2 := currency.PairStore{
|
||||
AssetEnabled: true,
|
||||
RequestFormat: ¤cy.PairFormat{Uppercase: true},
|
||||
ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: ":"},
|
||||
}
|
||||
|
||||
if err := e.SetAssetPairStore(asset.Spot, fmt1); err != nil {
|
||||
log.Errorf(log.ExchangeSys, "%s error storing %q default asset formats: %s", e.Name, asset.Spot, err)
|
||||
}
|
||||
if err := e.SetAssetPairStore(asset.Margin, fmt2); err != nil {
|
||||
log.Errorf(log.ExchangeSys, "%s error storing %q default asset formats: %s", e.Name, asset.Margin, err)
|
||||
}
|
||||
|
||||
// Fill out the capabilities/features that the exchange supports
|
||||
e.Features = exchange.Features{
|
||||
Supports: exchange.FeaturesSupported{
|
||||
{{ if .REST }} REST: true, {{ end }}
|
||||
{{ if .WS }} Websocket: true, {{ end }}
|
||||
{{ if .REST }}
|
||||
RESTCapabilities: protocol.Features{
|
||||
TickerFetching: true,
|
||||
OrderbookFetching: true,
|
||||
KlineFetching: true,
|
||||
TradeFetching: true,
|
||||
GetOrders: true,
|
||||
AccountInfo: true,
|
||||
AuthenticatedEndpoints: true,
|
||||
},
|
||||
{{ end }}
|
||||
{{ if .WS }}
|
||||
WebsocketCapabilities: protocol.Features{
|
||||
TickerFetching: true,
|
||||
OrderbookFetching: true,
|
||||
KlineFetching: true,
|
||||
TradeFetching: true,
|
||||
Subscribe: true,
|
||||
Unsubscribe: true,
|
||||
AuthenticatedEndpoints: true,
|
||||
},
|
||||
{{ end }}
|
||||
WithdrawPermissions: exchange.AutoWithdrawCrypto |
|
||||
exchange.AutoWithdrawFiat,
|
||||
Kline: kline.ExchangeCapabilitiesSupported{
|
||||
Intervals: false,
|
||||
},
|
||||
},
|
||||
|
||||
Enabled: exchange.FeaturesEnabled{
|
||||
AutoPairUpdates: true,
|
||||
// Kline: kline.ExchangeCapabilitiesEnabled{
|
||||
// Intervals: kline.DeployExchangeIntervals(
|
||||
// kline.IntervalCapacity{Interval: kline.OneMin},
|
||||
// ),
|
||||
// GlobalResultLimit: 2000,
|
||||
// },
|
||||
},
|
||||
{{ if .WS }} Subscriptions: defaultSubscriptions,{{ end }}
|
||||
}
|
||||
// TODO: SET THE EXCHANGES RATE LIMIT HERE
|
||||
var err error
|
||||
e.Requester, err = request.New(e.Name, common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout))
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
|
||||
// TODO: SET THE URLs HERE
|
||||
e.API.Endpoints = e.NewEndpoints()
|
||||
if err = e.API.Endpoints.SetDefaultEndpoints(map[exchange.URL]string{
|
||||
exchange.RestSpot: apiURL,
|
||||
{{ if .WS }} exchange.WebsocketSpot: wsAPIURL,{{ end }}
|
||||
}); err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
e.Websocket = websocket.NewManager()
|
||||
e.WebsocketResponseMaxLimit = exchange.DefaultWebsocketResponseMaxLimit
|
||||
e.WebsocketResponseCheckTimeout = exchange.DefaultWebsocketResponseCheckTimeout
|
||||
e.WebsocketOrderbookBufferLimit = exchange.DefaultWebsocketOrderbookBufferLimit
|
||||
}
|
||||
|
||||
// Setup takes in the supplied exchange configuration details and sets params
|
||||
func (e *Exchange) Setup(exch *config.Exchange) error {
|
||||
if err := exch.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if !exch.Enabled {
|
||||
e.SetEnabled(false)
|
||||
return nil
|
||||
}
|
||||
if err := e.SetupDefaults(exch); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
/*
|
||||
wsRunningEndpoint, err := e.API.Endpoints.GetURL(exchange.WebsocketSpot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If websocket is not supported, remove these websocket sections
|
||||
if err := e.Websocket.Setup(
|
||||
&websocket.ManagerSetup{
|
||||
ExchangeConfig: exch,
|
||||
DefaultURL: wsAPIURL,
|
||||
RunningURL: wsRunningEndpoint,
|
||||
Connector: e.WsConnect,
|
||||
Subscriber: e.Subscribe,
|
||||
Unsubscriber: e.Unsubscribe,
|
||||
GenerateSubscriptions: e.generateSubscriptions,
|
||||
Features: &e.Features.Supports.WebsocketCapabilities,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return e.Websocket.SetupNewConnection(&websocket.ConnectionSetup{
|
||||
URL: e.Websocket.GetWebsocketURL(),
|
||||
ResponseCheckTimeout: exch.WebsocketResponseCheckTimeout,
|
||||
ResponseMaxLimit: exch.WebsocketResponseMaxLimit,
|
||||
})
|
||||
*/
|
||||
return nil
|
||||
}
|
||||
|
||||
// FetchTradablePairs returns a list of the exchanges tradable pairs
|
||||
func (e *Exchange) FetchTradablePairs(ctx context.Context, a asset.Item) (currency.Pairs, error) {
|
||||
// Implement fetching the exchange available pairs if supported
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// UpdateTradablePairs updates the exchanges available pairs and stores them in the exchanges config
|
||||
func (e *Exchange) UpdateTradablePairs(ctx context.Context, forceUpdate bool) error {
|
||||
assetTypes := e.GetAssetTypes(false)
|
||||
for x := range assetTypes {
|
||||
pairs, err := e.FetchTradablePairs(ctx, assetTypes[x])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = e.UpdatePairs(pairs, assetTypes[x], false, forceUpdate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateTicker updates and returns the ticker for a currency pair
|
||||
func (e *Exchange) UpdateTicker(ctx context.Context, p currency.Pair, assetType asset.Item) (*ticker.Price, error) {
|
||||
// TODO: Replace this example code with exchange specific implementation
|
||||
/*
|
||||
tick, err := e.GetTickers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for y := range tick {
|
||||
cp, err := currency.NewPairFromString(tick[y].Symbol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = ticker.ProcessTicker(&ticker.Price{
|
||||
Last: tick[y].LastPrice,
|
||||
High: tick[y].HighPrice,
|
||||
Low: tick[y].LowPrice,
|
||||
Bid: tick[y].BidPrice,
|
||||
Ask: tick[y].AskPrice,
|
||||
Volume: tick[y].Volume,
|
||||
QuoteVolume: tick[y].QuoteVolume,
|
||||
Open: tick[y].OpenPrice,
|
||||
Close: tick[y].PrevClosePrice,
|
||||
Pair: cp,
|
||||
ExchangeName: e.Name,
|
||||
AssetType: assetType,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
*/
|
||||
return ticker.GetTicker(e.Name, p, assetType)
|
||||
}
|
||||
|
||||
// UpdateTickers updates all currency pairs of a given asset type
|
||||
func (e *Exchange) UpdateTickers(ctx context.Context, assetType asset.Item) error {
|
||||
// TODO: Replace this example code with exchange specific implementation
|
||||
/*
|
||||
tick, err := e.GetTickers()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for y := range tick {
|
||||
cp, err := currency.NewPairFromString(tick[y].Symbol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ticker.ProcessTicker(&ticker.Price{
|
||||
Last: tick[y].LastPrice,
|
||||
High: tick[y].HighPrice,
|
||||
Low: tick[y].LowPrice,
|
||||
Bid: tick[y].BidPrice,
|
||||
Ask: tick[y].AskPrice,
|
||||
Volume: tick[y].Volume,
|
||||
QuoteVolume: tick[y].QuoteVolume,
|
||||
Open: tick[y].OpenPrice,
|
||||
Close: tick[y].PrevClosePrice,
|
||||
Pair: cp,
|
||||
ExchangeName: e.Name,
|
||||
AssetType: assetType,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
*/
|
||||
return common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// UpdateOrderbook updates and returns the orderbook for a currency pair
|
||||
func (e *Exchange) UpdateOrderbook(ctx context.Context, pair currency.Pair, assetType asset.Item) (*orderbook.Book, error) {
|
||||
var err error
|
||||
pair, err = e.FormatExchangeCurrency(pair, assetType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO: Replace this example code with exchange specific implementation
|
||||
/*
|
||||
ob, err := e.GetOrderBook(pair.String(), 1000)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
*/
|
||||
book := &orderbook.Book{
|
||||
Exchange: e.Name,
|
||||
Pair: pair,
|
||||
Asset: assetType,
|
||||
ValidateOrderbook: e.ValidateOrderbook,
|
||||
}
|
||||
/*
|
||||
book.Bids = make([]orderbook.Level, len(ob.Bids))
|
||||
for x := range ob.Bids {
|
||||
book.Bids[x] = orderbook.Level{
|
||||
Amount: ob.Bids[x].Quantity,
|
||||
Price: ob.Bids[x].Price,
|
||||
}
|
||||
}
|
||||
|
||||
book.Asks = make([]orderbook.Level, len(ob.Asks))
|
||||
for x := range ob.Asks {
|
||||
book.Asks[x] = orderbook.Level{
|
||||
Amount: ob.Asks[x].Quantity,
|
||||
Price: ob.Asks[x].Price,
|
||||
}
|
||||
}
|
||||
*/
|
||||
if err := book.Process(); err != nil {
|
||||
return book, err
|
||||
}
|
||||
|
||||
return orderbook.Get(e.Name, pair, assetType)
|
||||
}
|
||||
|
||||
// UpdateAccountInfo retrieves balances for all enabled currencies
|
||||
func (e *Exchange) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (account.Holdings, error) {
|
||||
// If fetching requires more than one asset type please set
|
||||
// HasAssetTypeAccountSegregation to true in RESTCapabilities above.
|
||||
return account.Holdings{}, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetAccountFundingHistory returns funding history, deposits and withdrawals
|
||||
func (e *Exchange) GetAccountFundingHistory(ctx context.Context) ([]exchange.FundingHistory, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetWithdrawalsHistory returns previous withdrawals data
|
||||
func (e *Exchange) GetWithdrawalsHistory(ctx context.Context, c currency.Code, a asset.Item) ([]exchange.WithdrawalHistory, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetRecentTrades returns the most recent trades for a currency and asset
|
||||
func (e *Exchange) GetRecentTrades(ctx context.Context, p currency.Pair, assetType asset.Item) ([]trade.Data, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetHistoricTrades returns historic trade data within the timeframe provided
|
||||
func (e *Exchange) GetHistoricTrades(ctx context.Context, p currency.Pair, assetType asset.Item, timestampStart, timestampEnd time.Time) ([]trade.Data, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetServerTime returns the current exchange server time.
|
||||
func (e *Exchange) GetServerTime(ctx context.Context, a asset.Item) (time.Time, error) {
|
||||
return time.Time{}, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func (e *Exchange) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate(e.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
/* TODO: When an order has been submitted you can use this helpful constructor to
|
||||
return. Please add any additional order details to the
|
||||
order.SubmitResponse if you think they are applicable.
|
||||
resp, err := s.DeriveSubmitResponse(newOrderID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Date = exampleTime // e.g. If this is supplied by the exchanges API.
|
||||
return resp, nil
|
||||
*/
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// ModifyOrder will allow changing of orderbook placements and limit to market conversions
|
||||
func (e *Exchange) ModifyOrder(ctx context.Context, action *order.Modify) (*order.ModifyResponse, error) {
|
||||
if err := action.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO: When an order has been modified you can use this helpful constructor to
|
||||
// return. Please add any additional order details to the
|
||||
// order.ModifyResponse if you think they are applicable.
|
||||
// resp, err := action.DeriveModifyResponse()
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// resp.OrderID = maybeANewOrderID // e.g. If this is supplied by the exchanges API.
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// CancelOrder cancels an order by its corresponding ID number
|
||||
func (e *Exchange) CancelOrder(ctx context.Context, ord *order.Cancel) error {
|
||||
// if err := ord.Validate(ord.StandardCancel()); err != nil {
|
||||
// return err
|
||||
// }
|
||||
return common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// CancelBatchOrders cancels orders by their corresponding ID numbers
|
||||
func (e *Exchange) CancelBatchOrders(ctx context.Context, orders []order.Cancel) (*order.CancelBatchResponse, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// CancelAllOrders cancels all orders associated with a currency pair
|
||||
func (e *Exchange) CancelAllOrders(ctx context.Context, orderCancellation *order.Cancel) (order.CancelAllResponse, error) {
|
||||
// if err := orderCancellation.Validate(); err != nil {
|
||||
// return order.CancelAllResponse{}, err
|
||||
// }
|
||||
return order.CancelAllResponse{}, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetOrderInfo returns order information based on order ID
|
||||
func (e *Exchange) GetOrderInfo(ctx context.Context, orderID string, pair currency.Pair, assetType asset.Item) (*order.Detail, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetDepositAddress returns a deposit address for a specified currency
|
||||
func (e *Exchange) GetDepositAddress(ctx context.Context, c currency.Code, accountID string, chain string) (*deposit.Address, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetAvailableTransferChains returns the available transfer blockchains for the specific cryptocurrency
|
||||
func (e *Exchange) GetAvailableTransferChains(ctx context.Context, cryptocurrency currency.Code) ([]string, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is submitted
|
||||
func (e *Exchange) WithdrawCryptocurrencyFunds(ctx context.Context, withdrawRequest *withdraw.Request) (*withdraw.ExchangeResponse, error) {
|
||||
// if err := withdrawRequest.Validate(); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// WithdrawFiatFunds returns a withdrawal ID when a withdrawal is submitted
|
||||
func (e *Exchange) WithdrawFiatFunds(_ context.Context, withdrawRequest *withdraw.Request) (*withdraw.ExchangeResponse, error) {
|
||||
// if err := withdrawRequest.Validate(); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a withdrawal is submitted
|
||||
func (e *Exchange) WithdrawFiatFundsToInternationalBank(_ context.Context, withdrawRequest *withdraw.Request) (*withdraw.ExchangeResponse, error) {
|
||||
// if err := withdrawRequest.Validate(); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetActiveOrders retrieves any orders that are active/open
|
||||
func (e *Exchange) GetActiveOrders(ctx context.Context, getOrdersRequest *order.MultiOrderRequest) (order.FilteredOrders, error) {
|
||||
// if err := getOrdersRequest.Validate(); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetOrderHistory retrieves account order information
|
||||
// Can Limit response to specific order status
|
||||
func (e *Exchange) GetOrderHistory(ctx context.Context, getOrdersRequest *order.MultiOrderRequest) (order.FilteredOrders, error) {
|
||||
// if err := getOrdersRequest.Validate(); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetFeeByType returns an estimate of fee based on the type of transaction
|
||||
func (e *Exchange) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
return 0, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// ValidateAPICredentials validates current credentials used for wrapper
|
||||
func (e *Exchange) ValidateAPICredentials(ctx context.Context, assetType asset.Item) error {
|
||||
_, err := e.UpdateAccountInfo(ctx, assetType)
|
||||
return e.CheckTransientError(err)
|
||||
}
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func (e *Exchange) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetHistoricCandlesExtended returns candles between a time period for a set time interval
|
||||
func (e *Exchange) GetHistoricCandlesExtended(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetLeverage gets the account's initial leverage for the asset type and pair
|
||||
func (e *Exchange) GetLeverage(_ context.Context, _ asset.Item, _ currency.Pair, _ margin.Type, _ order.Side) (float64, error) {
|
||||
return -1, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetFuturesContractDetails returns all contracts from the exchange by asset type
|
||||
func (e *Exchange) GetFuturesContractDetails(context.Context, asset.Item) ([]futures.Contract, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetLatestFundingRates returns the latest funding rates data
|
||||
func (e *Exchange) GetLatestFundingRates(_ context.Context, _ *fundingrate.LatestRateRequest) ([]fundingrate.LatestRateResponse, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetHistoricalFundingRates returns funding rates for a given asset and currency for a time period
|
||||
func (e *Exchange) GetHistoricalFundingRates(_ context.Context, r *fundingrate.HistoricalRatesRequest) (*fundingrate.HistoricalRates, error) {
|
||||
if r == nil {
|
||||
return nil, common.ErrNilPointer
|
||||
}
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetOpenInterest returns the open interest rate for a given asset pair
|
||||
func (e *Exchange) GetOpenInterest(_ context.Context, _ ...key.PairAsset) ([]futures.OpenInterest, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetCurrencyTradeURL returns the URL to the exchange's trade page for the given asset and currency pair
|
||||
func (e *Exchange) GetCurrencyTradeURL(_ context.Context, a asset.Item, cp currency.Pair) (string, error) {
|
||||
_, err := e.CurrencyPairs.IsPairEnabled(cp, a)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "", common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// UpdateOrderExecutionLimits updates order execution limits
|
||||
func (e *Exchange) UpdateOrderExecutionLimits(_ context.Context, _ asset.Item) error {
|
||||
return common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// SetLeverage sets the account's initial leverage for the asset type and pair
|
||||
func (e *Exchange) SetLeverage(_ context.Context, _ asset.Item, _ currency.Pair, _ margin.Type, _ float64, _ order.Side) error {
|
||||
return common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
{{end}}
|
||||
@@ -1,473 +0,0 @@
|
||||
{{define "wrapper"}}
|
||||
package {{.Name}}
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/deposit"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/fundingrate"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/futures"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/protocol"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/trade"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchange/websocket"
|
||||
"github.com/thrasher-corp/gocryptotrader/log"
|
||||
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
|
||||
)
|
||||
|
||||
// SetDefaults sets the basic defaults for {{.CapitalName}}
|
||||
func ({{.Variable}} *{{.CapitalName}}) SetDefaults() {
|
||||
{{.Variable}}.Name = "{{.CapitalName}}"
|
||||
{{.Variable}}.Enabled = true
|
||||
{{.Variable}}.Verbose = true
|
||||
{{.Variable}}.API.CredentialsValidator.RequiresKey = true
|
||||
{{.Variable}}.API.CredentialsValidator.RequiresSecret = true
|
||||
|
||||
// If using only one pair format for request and configuration, across all
|
||||
// supported asset types either SPOT and FUTURES etc. You can use the
|
||||
// example below:
|
||||
|
||||
// Request format denotes what the pair as a string will be, when you send
|
||||
// a request to an exchange.
|
||||
requestFmt := ¤cy.PairFormat{/*Set pair request formatting details here for e.g.*/ Uppercase: true, Delimiter: ":"}
|
||||
// Config format denotes what the pair as a string will be, when saved to
|
||||
// the config.json file.
|
||||
configFmt := ¤cy.PairFormat{/*Set pair request formatting details here*/}
|
||||
err := {{.Variable}}.SetGlobalPairsManager(requestFmt, configFmt, /*multiple assets can be set here using the asset package ie asset.Spot*/)
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
|
||||
// If assets require multiple differences in formatting for request and
|
||||
// configuration, another exchange method can be be used e.g. futures
|
||||
// contracts require a dash as a delimiter rather than an underscore. You
|
||||
// can use this example below:
|
||||
|
||||
fmt1 := currency.PairStore{
|
||||
AssetEnabled: true,
|
||||
RequestFormat: ¤cy.PairFormat{Uppercase: true},
|
||||
ConfigFormat: ¤cy.PairFormat{Uppercase: true},
|
||||
}
|
||||
|
||||
fmt2 := currency.PairStore{
|
||||
AssetEnabled: true,
|
||||
RequestFormat: ¤cy.PairFormat{Uppercase: true},
|
||||
ConfigFormat: ¤cy.PairFormat{Uppercase: true, Delimiter: ":"},
|
||||
}
|
||||
|
||||
err = {{.Variable}}.SetAssetPairStore(asset.Spot, fmt1)
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys, "%s error storing %q default asset formats: %s", {{.Variable}}.Name, asset.Spot, err)
|
||||
}
|
||||
err = {{.Variable}}.SetAssetPairStore(asset.Margin, fmt2)
|
||||
if err != nil {
|
||||
log.Errorf(log.ExchangeSys, "%s error storing %q default asset formats: %s", {{.Variable}}.Name, asset.Margin, err)
|
||||
}
|
||||
|
||||
// Fill out the capabilities/features that the exchange supports
|
||||
{{.Variable}}.Features = exchange.Features{
|
||||
Supports: exchange.FeaturesSupported{
|
||||
{{ if .REST }} REST: true, {{ end }}
|
||||
{{ if .WS }} Websocket: true, {{ end }}
|
||||
RESTCapabilities: protocol.Features{
|
||||
TickerFetching: true,
|
||||
OrderbookFetching: true,
|
||||
},
|
||||
WebsocketCapabilities: protocol.Features{
|
||||
TickerFetching: true,
|
||||
OrderbookFetching: true,
|
||||
},
|
||||
WithdrawPermissions: exchange.AutoWithdrawCrypto |
|
||||
exchange.AutoWithdrawFiat,
|
||||
},
|
||||
Enabled: exchange.FeaturesEnabled{
|
||||
AutoPairUpdates: true,
|
||||
},
|
||||
}
|
||||
// NOTE: SET THE EXCHANGES RATE LIMIT HERE
|
||||
{{.Variable}}.Requester, err = request.New({{.Variable}}.Name,
|
||||
common.NewHTTPClientWithTimeout(exchange.DefaultHTTPTimeout))
|
||||
if err != nil {
|
||||
log.Errorln(log.ExchangeSys, err)
|
||||
}
|
||||
|
||||
// NOTE: SET THE URLs HERE
|
||||
{{.Variable}}.API.Endpoints = {{.Variable}}.NewEndpoints()
|
||||
{{.Variable}}.API.Endpoints.SetDefaultEndpoints(map[exchange.URL]string{
|
||||
exchange.RestSpot: {{.Name}}APIURL,
|
||||
// exchange.WebsocketSpot: {{.Name}}WSAPIURL,
|
||||
})
|
||||
{{.Variable}}.Websocket = websocket.NewManager()
|
||||
{{.Variable}}.WebsocketResponseMaxLimit = exchange.DefaultWebsocketResponseMaxLimit
|
||||
{{.Variable}}.WebsocketResponseCheckTimeout = exchange.DefaultWebsocketResponseCheckTimeout
|
||||
{{.Variable}}.WebsocketOrderbookBufferLimit = exchange.DefaultWebsocketOrderbookBufferLimit
|
||||
}
|
||||
|
||||
// Setup takes in the supplied exchange configuration details and sets params
|
||||
func ({{.Variable}} *{{.CapitalName}}) Setup(exch *config.Exchange) error {
|
||||
err := exch.Validate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exch.Enabled {
|
||||
{{.Variable}}.SetEnabled(false)
|
||||
return nil
|
||||
}
|
||||
err = {{.Variable}}.SetupDefaults(exch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
/*
|
||||
wsRunningEndpoint, err := {{.Variable}}.API.Endpoints.GetURL(exchange.WebsocketSpot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If websocket is supported, please fill out the following
|
||||
|
||||
err = {{.Variable}}.Websocket.Setup(
|
||||
&websocket.ManagerSetup{
|
||||
ExchangeConfig: exch,
|
||||
DefaultURL: {{.Name}}WSAPIURL,
|
||||
RunningURL: wsRunningEndpoint,
|
||||
Connector: {{.Variable}}.WsConnect,
|
||||
Subscriber: {{.Variable}}.Subscribe,
|
||||
UnSubscriber: {{.Variable}}.Unsubscribe,
|
||||
Features: &{{.Variable}}.Features.Supports.WebsocketCapabilities,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
{{.Variable}}.WebsocketConn = &websocket.WebsocketConnection{
|
||||
ExchangeName: {{.Variable}}.Name,
|
||||
URL: {{.Variable}}.Websocket.GetWebsocketURL(),
|
||||
ProxyURL: {{.Variable}}.Websocket.GetProxyAddress(),
|
||||
Verbose: {{.Variable}}.Verbose,
|
||||
ResponseCheckTimeout: exch.WebsocketResponseCheckTimeout,
|
||||
ResponseMaxLimit: exch.WebsocketResponseMaxLimit,
|
||||
}
|
||||
*/
|
||||
return nil
|
||||
}
|
||||
|
||||
// FetchTradablePairs returns a list of the exchanges tradable pairs
|
||||
func ({{.Variable}} *{{.CapitalName}}) FetchTradablePairs(ctx context.Context, a asset.Item) (currency.Pairs, error) {
|
||||
// Implement fetching the exchange available pairs if supported
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// UpdateTradablePairs updates the exchanges available pairs and stores
|
||||
// them in the exchanges config
|
||||
func ({{.Variable}} *{{.CapitalName}}) UpdateTradablePairs(ctx context.Context, forceUpdate bool) error {
|
||||
assetTypes := {{.Variable}}.GetAssetTypes(false)
|
||||
for x := range assetTypes {
|
||||
pairs, err := {{.Variable}}.FetchTradablePairs(ctx, assetTypes[x])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = {{.Variable}}.UpdatePairs(pairs, assetTypes[x], false, forceUpdate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// UpdateTicker updates and returns the ticker for a currency pair
|
||||
func ({{.Variable}} *{{.CapitalName}}) UpdateTicker(ctx context.Context, p currency.Pair, assetType asset.Item) (*ticker.Price, error) {
|
||||
// NOTE: EXAMPLE FOR GETTING TICKER PRICE
|
||||
/*
|
||||
tickerPrice := new(ticker.Price)
|
||||
tick, err := {{.Variable}}.GetTicker(p.String())
|
||||
if err != nil {
|
||||
return tickerPrice, err
|
||||
}
|
||||
tickerPrice = &ticker.Price{
|
||||
High: tick.High,
|
||||
Low: tick.Low,
|
||||
Bid: tick.Bid,
|
||||
Ask: tick.Ask,
|
||||
Open: tick.Open,
|
||||
Close: tick.Close,
|
||||
Pair: p,
|
||||
}
|
||||
err = ticker.ProcessTicker({{.Variable}}.Name, tickerPrice, assetType)
|
||||
if err != nil {
|
||||
return tickerPrice, err
|
||||
}
|
||||
*/
|
||||
return ticker.GetTicker({{.Variable}}.Name, p, assetType)
|
||||
}
|
||||
|
||||
// UpdateTickers updates all currency pairs of a given asset type
|
||||
func ({{.Variable}} *{{.CapitalName}}) UpdateTickers(ctx context.Context, assetType asset.Item) error {
|
||||
// NOTE: EXAMPLE FOR GETTING TICKER PRICE
|
||||
/*
|
||||
tick, err := {{.Variable}}.GetTickers()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for y := range tick {
|
||||
cp, err := currency.NewPairFromString(tick[y].Symbol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ticker.ProcessTicker(&ticker.Price{
|
||||
Last: tick[y].LastPrice,
|
||||
High: tick[y].HighPrice,
|
||||
Low: tick[y].LowPrice,
|
||||
Bid: tick[y].BidPrice,
|
||||
Ask: tick[y].AskPrice,
|
||||
Volume: tick[y].Volume,
|
||||
QuoteVolume: tick[y].QuoteVolume,
|
||||
Open: tick[y].OpenPrice,
|
||||
Close: tick[y].PrevClosePrice,
|
||||
Pair: cp,
|
||||
ExchangeName: b.Name,
|
||||
AssetType: assetType,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
*/
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateOrderbook updates and returns the orderbook for a currency pair
|
||||
func ({{.Variable}} *{{.CapitalName}}) UpdateOrderbook(ctx context.Context, pair currency.Pair, assetType asset.Item) (*orderbook.Book, error) {
|
||||
book := &orderbook.Book{
|
||||
Exchange: {{.Variable}}.Name,
|
||||
Pair: pair,
|
||||
Asset: assetType,
|
||||
ValidateOrderbook: {{.Variable}}.ValidateOrderbook,
|
||||
}
|
||||
|
||||
// NOTE: UPDATE ORDERBOOK EXAMPLE
|
||||
/*
|
||||
orderbookNew, err := {{.Variable}}.GetOrderBook(exchange.FormatExchangeCurrency({{.Variable}}.Name, p).String(), 1000)
|
||||
if err != nil {
|
||||
return book, err
|
||||
}
|
||||
|
||||
book.Bids = make([]orderbook.Level, len(orderbookNew.Bids))
|
||||
for x := range orderbookNew.Bids {
|
||||
book.Bids[x] = orderbook.Level{
|
||||
Amount: orderbookNew.Bids[x].Quantity,
|
||||
Price: orderbookNew.Bids[x].Price,
|
||||
}
|
||||
}
|
||||
|
||||
book.Asks = make([]orderbook.Level, len(orderbookNew.Asks))
|
||||
for x := range orderbookNew.Asks {
|
||||
book.Asks[x] = orderbook.Level{
|
||||
Amount: orderBookNew.Asks[x].Quantity,
|
||||
Price: orderBookNew.Asks[x].Price,
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
err := book.Process()
|
||||
if err != nil {
|
||||
return book, err
|
||||
}
|
||||
|
||||
return orderbook.Get({{.Variable}}.Name, pair, assetType)
|
||||
}
|
||||
|
||||
// UpdateAccountInfo retrieves balances for all enabled currencies
|
||||
func ({{.Variable}} *{{.CapitalName}}) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (account.Holdings, error) {
|
||||
// If fetching requires more than one asset type please set
|
||||
// HasAssetTypeAccountSegregation to true in RESTCapabilities above.
|
||||
return account.Holdings{}, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetFundingHistory returns funding history, deposits and
|
||||
// withdrawals
|
||||
func ({{.Variable}} *{{.CapitalName}}) GetAccountFundingHistory(ctx context.Context) ([]exchange.FundingHistory, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetWithdrawalsHistory returns previous withdrawals data
|
||||
func ({{.Variable}} *{{.CapitalName}}) GetWithdrawalsHistory(ctx context.Context, c currency.Code, a asset.Item) ([]exchange.WithdrawalHistory, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetRecentTrades returns the most recent trades for a currency and asset
|
||||
func ({{.Variable}} *{{.CapitalName}}) GetRecentTrades(ctx context.Context, p currency.Pair, assetType asset.Item) ([]trade.Data, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetHistoricTrades returns historic trade data within the timeframe provided
|
||||
func ({{.Variable}} *{{.CapitalName}}) GetHistoricTrades(ctx context.Context, p currency.Pair, assetType asset.Item, timestampStart, timestampEnd time.Time) ([]trade.Data, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
|
||||
// GetServerTime returns the current exchange server time.
|
||||
func ({{.Variable}} *{{.CapitalName}}) GetServerTime(ctx context.Context, a asset.Item) (time.Time, error) {
|
||||
return time.Time{}, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
|
||||
// SubmitOrder submits a new order
|
||||
func ({{.Variable}} *{{.CapitalName}}) SubmitOrder(ctx context.Context, s *order.Submit) (*order.SubmitResponse, error) {
|
||||
if err := s.Validate({{.Variable}}.GetTradingRequirements()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// When an order has been submitted you can use this helpful constructor to
|
||||
// return. Please add any additional order details to the
|
||||
// order.SubmitResponse if you think they are applicable.
|
||||
// resp, err := s.DeriveSubmitResponse( /*newOrderID*/)
|
||||
// if err != nil {
|
||||
// return nil, nil
|
||||
// }
|
||||
// resp.Date = exampleTime // e.g. If this is supplied by the exchanges API.
|
||||
// return resp, nil
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// ModifyOrder will allow of changing orderbook placement and limit to
|
||||
// market conversion
|
||||
func ({{.Variable}} *{{.CapitalName}}) ModifyOrder(ctx context.Context, action *order.Modify) (*order.ModifyResponse, error) {
|
||||
if err := action.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// When an order has been modified you can use this helpful constructor to
|
||||
// return. Please add any additional order details to the
|
||||
// order.ModifyResponse if you think they are applicable.
|
||||
// resp, err := action.DeriveModifyResponse()
|
||||
// if err != nil {
|
||||
// return nil, nil
|
||||
// }
|
||||
// resp.OrderID = maybeANewOrderID // e.g. If this is supplied by the exchanges API.
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// CancelOrder cancels an order by its corresponding ID number
|
||||
func ({{.Variable}} *{{.CapitalName}}) CancelOrder(ctx context.Context, ord *order.Cancel) error {
|
||||
// if err := ord.Validate(ord.StandardCancel()); err != nil {
|
||||
// return err
|
||||
// }
|
||||
return common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// CancelBatchOrders cancels orders by their corresponding ID numbers
|
||||
func ({{.Variable}} *{{.CapitalName}}) CancelBatchOrders(ctx context.Context, orders []order.Cancel) (*order.CancelBatchResponse, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// CancelAllOrders cancels all orders associated with a currency pair
|
||||
func ({{.Variable}} *{{.CapitalName}}) CancelAllOrders(ctx context.Context, orderCancellation *order.Cancel) (order.CancelAllResponse, error) {
|
||||
// if err := orderCancellation.Validate(); err != nil {
|
||||
// return err
|
||||
// }
|
||||
return order.CancelAllResponse{}, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetOrderInfo returns order information based on order ID
|
||||
func ({{.Variable}} *{{.CapitalName}}) GetOrderInfo(ctx context.Context, orderID string, pair currency.Pair, assetType asset.Item) (*order.Detail, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetDepositAddress returns a deposit address for a specified currency
|
||||
func ({{.Variable}} *{{.CapitalName}}) GetDepositAddress(ctx context.Context, c currency.Code, accountID string, chain string) (*deposit.Address, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func ({{.Variable}} *{{.CapitalName}}) WithdrawCryptocurrencyFunds(ctx context.Context, withdrawRequest *withdraw.Request) (*withdraw.ExchangeResponse, error) {
|
||||
// if err := withdrawRequest.Validate(); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// WithdrawFiatFunds returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func ({{.Variable}} *{{.CapitalName}}) WithdrawFiatFunds(ctx context.Context, withdrawRequest *withdraw.Request) (*withdraw.ExchangeResponse, error) {
|
||||
// if err := withdrawRequest.Validate(); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// WithdrawFiatFundsToInternationalBank returns a withdrawal ID when a withdrawal is
|
||||
// submitted
|
||||
func ({{.Variable}} *{{.CapitalName}}) WithdrawFiatFundsToInternationalBank(ctx context.Context, withdrawRequest *withdraw.Request) (*withdraw.ExchangeResponse, error) {
|
||||
// if err := withdrawRequest.Validate(); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetActiveOrders retrieves any orders that are active/open
|
||||
func ({{.Variable}} *{{.CapitalName}}) GetActiveOrders(ctx context.Context, getOrdersRequest *order.MultiOrderRequest) (order.FilteredOrders, error) {
|
||||
// if err := getOrdersRequest.Validate(); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetOrderHistory retrieves account order information
|
||||
// Can Limit response to specific order status
|
||||
func ({{.Variable}} *{{.CapitalName}}) GetOrderHistory(ctx context.Context, getOrdersRequest *order.MultiOrderRequest) (order.FilteredOrders, error) {
|
||||
// if err := getOrdersRequest.Validate(); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetFeeByType returns an estimate of fee based on the type of transaction
|
||||
func ({{.Variable}} *{{.CapitalName}}) GetFeeByType(ctx context.Context, feeBuilder *exchange.FeeBuilder) (float64, error) {
|
||||
return 0, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// ValidateAPICredentials validates current credentials used for wrapper
|
||||
func ({{.Variable}} *{{.CapitalName}}) ValidateAPICredentials(ctx context.Context, assetType asset.Item) error {
|
||||
_, err := {{.Variable}}.UpdateAccountInfo(ctx, assetType)
|
||||
return {{.Variable}}.CheckTransientError(err)
|
||||
}
|
||||
|
||||
// GetHistoricCandles returns candles between a time period for a set time interval
|
||||
func ({{.Variable}} *{{.CapitalName}}) GetHistoricCandles(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetHistoricCandlesExtended returns candles between a time period for a set time interval
|
||||
func ({{.Variable}} *{{.CapitalName}}) GetHistoricCandlesExtended(ctx context.Context, pair currency.Pair, a asset.Item, interval kline.Interval, start, end time.Time) (*kline.Item, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetFuturesContractDetails returns all contracts from the exchange by asset type
|
||||
func ({{.Variable}} *{{.CapitalName}}) GetFuturesContractDetails(context.Context, asset.Item) ([]futures.Contract, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// GetLatestFundingRates returns the latest funding rates data
|
||||
func ({{.Variable}} *{{.CapitalName}}) GetLatestFundingRates(_ context.Context, _ *fundingrate.LatestRateRequest) ([]fundingrate.LatestRateResponse, error) {
|
||||
return nil, common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
// UpdateOrderExecutionLimits updates order execution limits
|
||||
func ({{.Variable}} *{{.CapitalName}}) UpdateOrderExecutionLimits(_ context.Context, _ asset.Item) error {
|
||||
return common.ErrNotYetImplemented
|
||||
}
|
||||
|
||||
{{end}}
|
||||
@@ -126,7 +126,7 @@ func main() {
|
||||
pf.Subtotal = y.Balance
|
||||
}
|
||||
} else {
|
||||
bf := bitfinex.Bitfinex{}
|
||||
bf := bitfinex.Exchange{}
|
||||
bf.SetDefaults()
|
||||
bf.Verbose = false
|
||||
pair := "t" + y.Coin.String() + currency.USD.String()
|
||||
|
||||
Reference in New Issue
Block a user