Type/to search
8
Follow
1364
Followers
Contoh Kontrak Perjanjian Umum Penemu Akses
Discussions
Created 2021-09-14 15:00:01  Updated 2024-12-04 21:17:44
 2
 2179

img

Contoh Kontrak Perjanjian Umum Penemu Akses

Baru-baru ini, beberapa pengguna telah membicarakan tentangAOFEXPertukaran ini, mengingat tidak ada contoh di FMZ tentang cara menghubungkan ke antarmuka REST dari pertukaran kontrak. Artikel ini akan fokus pada aksesAOFEXAmbil ini sebagai contoh untuk menjelaskan cara mengakses kontrak Exchange.

Ada perbedaan antara bursa spot dan bursa berjangka di FMZ. Misalnya, tiga bursa utama yang kita kenal memiliki perdagangan spot dan perdagangan kontrak. Antarmuka API pasar yang berbeda-beda ini juga berbeda, dan beberapa bahkan memiliki sistem API yang sepenuhnya terpisah dan independen. Oleh karena itu, saat mengemas Bursa ini di FMZ, perbedaan dibuat antara spot dan futures.

Sudah banyak contoh penggunaan protokol umum FMZ untuk merangkum pertukaran spot dalam komunitas dan dokumen platform FMZ, tetapi tidak ada contoh lengkap untuk merangkum pertukaran kontrak. Namun, program plug-in protokol umum dari versi futures yang dikemas pada dasarnya sama dengan versi spot, kecuali memiliki beberapa antarmuka tambahan.

Dokumen protokol umum FMZ: https://www.fmz.com/bbs-topic/1052
Dokumen ini dilengkapi dengan akses protokol umum pertukaran spot DEMO

Antarmuka yang menemukan objek pertukaran dan objek pertukaran berjangka perlu merangkum

Antarmuka utama objek pertukaran spot

  • exchange.GetTicker()
    Dapatkan data pasar tick untuk spot dan futures.

  • exchange.GetDepth()
    Dapatkan data buku pesanan untuk spot dan futures.

  • exchange.GetTrades()
    Memperoleh data arus pesanan (catatan transaksi pasar), baik untuk spot maupun futures.

  • exchange.GetRecords()
    Untuk memperoleh data K-line, diperlukan data spot dan futures.

  • exchange.GetAccount()
    Dapatkan data aset akun untuk spot dan futures.

  • exchange.Buy()
    Untuk menempatkan pesanan beli, diperlukan baik spot maupun futures.

  • exchange.Sell()
    Untuk menempatkan pesanan jual, diperlukan baik spot maupun futures.

  • exchange.GetOrder()
    Dapatkan data pesanan dari ID yang ditentukan, baik spot maupun futures.

  • exchange.GetOrders()
    Dapatkan order tertunda yang saat ini aktif, baik spot maupun futures.

  • exchange.CancelOrder()
    Batalkan pesanan dengan ID yang ditentukan, baik untuk spot maupun futures.

Selain merangkum antarmuka objek pertukaran spot ini, objek pertukaran berjangka juga perlu merangkum fungsi antarmuka yang digunakan oleh berjangka.

  • exchange.SetMarginLevel()
    Tetapkan nilai leverage untuk simbol saat ini.

  • exchange.SetDirection()
    Tetapkan arah perdagangan produk saat ini, yaitu buka posisi panjang/buka posisi pendek/tutup posisi panjang/tutup posisi pendek.

  • exchange.SetContractType()
    Tetapkan kode kontrak saat ini. Karena kontrak berjangka memiliki kontrak yang bersifat terus-menerus (swap)、Kontrak Pengiriman(quarterQuarterly), dll., masing-masing memiliki kode kontraknya sendiri yang ditetapkan di FMZ. Untuk detailnya, silakan lihat dokumen API FMZ. Pengaturan ini juga perlu diikuti saat mengenkapsulasi, jika tidak, strategi lama yang ada mungkin tidak berfungsi dengan baik.

  • exchange.GetPosition()
    Dapatkan data posisi saat ini. Di sini kita dapat melihat bahwa tidak ada konsep posisi dalam perdagangan spot. Posisi logis hanya dapat dihitung dengan membandingkan perubahan akun. Namun, kontrak berjangka memang memiliki posisi.

Data badan dalam permintaan yang dikirim oleh kustodian ke plug-in protokol universal saat memanggil antarmuka khusus berjangka dalam strategi

Mengambil pertukaran AOFEX sebagai contoh, jika Anda mengonfigurasi objek pertukaran protokol umum pada FMZ, KUNCI API yang diisi adalah:

  • accessKey : 212f54a1-1c88-1bf5-54a1-f7bf52b3256c
  • secretKey : 7RJPKpBJMBkUL87RJPKpkULJPSUpsaKpUL83ysDs

img

Pada halaman konfigurasi protokol umum FMZ adaaccessKeyDansecretKeyKotak input, setelah mengonfigurasi objek pertukaran protokol universal, data format JSON dari Badan dalam permintaan yang diterima saat plug-in protokol universal sedang berjalanaccessKeyNilai bidang tersebut adalah212f54a1-1c88-1bf5-54a1-f7bf52b3256csecret_keyNilai bidang tersebut adalah7RJPKpBJMBkUL87RJPKpkULJPSUpsaKpUL83ysDs

Saat memanggil antarmuka berikut, host akan mengeluarkan permintaan RPC ke plug-in protokol umum sebagai berikut:

  • Ketika kebijakan tersebut disebutexchange.SetMarginLevel(10)Ketika data dalam badan permintaan adalah:

    { "access_key":"212f54a1-1c88-1bf5-54a1-f7bf52b3256c", "method":"io", "nonce":1631858961289247000, "params":{"args":[10],"code":0}, "secret_key":"7RJPKpBJMBkUL87RJPKpkULJPSUpsaKpUL83ysDs" }

    Panggil exchange.SetMarginLevel(10) dengan 10 sebagai parameter.

  • Ketika kebijakan tersebut disebutexchange.SetDirection("buy")Ketika data dalam badan permintaan adalah:

    { "access_key":"212f54a1-1c88-1bf5-54a1-f7bf52b3256c", "method":"io", "nonce":1631860438946922000, "params":{"args":["buy"],"code":1}, "secret_key":"7RJPKpBJMBkUL87RJPKpkULJPSUpsaKpUL83ysDs" }

    Panggil exchange.SetDirection("buy") dan berikan "buy" sebagai parameter.

  • Ketika kebijakan tersebut disebutexchange.SetContractType("swap")Ketika data dalam badan permintaan adalah:

    { "access_key":"212f54a1-1c88-1bf5-54a1-f7bf52b3256c", "method":"io", "nonce":1631860847525039000, "params":{"args":["swap"],"code":2}, "secret_key":"7RJPKpBJMBkUL87RJPKpkULJPSUpsaKpUL83ysDs" }

    Panggil exchange.SetContractType("swap") dan berikan "swap" sebagai parameter.

  • Ketika kebijakan tersebut disebutexchange.GetPosition()Ketika data dalam badan permintaan adalah:

    { "access_key":"212f54a1-1c88-1bf5-54a1-f7bf52b3256c", "method":"io", "nonce":1631860996119505000, "params":{"args":[],"code":3}, "secret_key":"7RJPKpBJMBkUL87RJPKpkULJPSUpsaKpUL83ysDs" }

    Saat memanggil exchange.GetPosition(), tidak ada parameter yang dilewatkan.

Amati data JSON dalam Badan permintaan di atas dan temukan bahwa:

  • Ketika fungsi khusus objek bursa berjangka dipanggil, badan permintaanmethodNilai bidang adalahio
  • Membedakan fungsi-fungsi ini memerlukanparamsDi lapangancodePenghakiman, yaitu:
    • codeuntuk0YaSetMarginLevel
    • codeuntuk1YaSetDirection
    • codeuntuk2YaSetContractType
    • codeuntuk3YaGetPosition
  • Saat fungsi spesifik objek pertukaran berjangka ini dipanggil, parameter yang dilewatkan ada di badan permintaan.paramsBidangargstengah.

Dibandingkan dengan contoh plug-in bahasa Go yang ada, Anda perluOnPostBuat ekstensi pada fungsi:
Lihat kode berikut untuk "Fungsi yang dibutuhkan untuk memperluas objek pertukaran berjangka"Lokasi komentar.

func OnPost(w http.ResponseWriter, r *http.Request) { var ret interface{} defer func() { if e := recover(); e != nil { if ee, ok := e.(error); ok { e = ee.Error() } ret = map[string]string{"error": fmt.Sprintf("%v", e)} } b, _ := json.Marshal(ret) w.Write(b) }() b, err := ioutil.ReadAll(r.Body) if err != nil { panic(err) } var request RpcRequest err = json.Unmarshal(b, &request) if err != nil { panic(err) } e := newZG(request.AccessKey, request.SecretKey) var symbol string if _, ok := request.Params["symbol"]; ok { symbol = strings.ToUpper(request.Params["symbol"].(string)) } var data interface{} switch request.Method { case "ticker": data, err = e.GetTicker(symbol, "GET") case "depth": data, err = e.GetDepth(symbol, "GET") case "trades": data, err = e.GetTrades(symbol, "GET") case "records": data, err = e.GetRecords(toInt64(request.Params["period"]), symbol, "GET") case "accounts": data, err = e.GetAccount(symbol, "GET") case "trade": side := request.Params["type"].(string) if side == "buy" { side = "BUY" } else { side = "SELL" } price := toFloat(request.Params["price"]) amount := toFloat(request.Params["amount"]) data, err = e.Trade(side, price, amount, symbol, "POST") case "orders": data, err = e.GetOrders(symbol, "POST") case "order": data, err = e.GetOrder(toString(request.Params["id"]), symbol, "POST") case "cancel": data, err = e.CancelOrder(toString(request.Params["id"]), symbol, "POST") default: if strings.HasPrefix(request.Method, "__api_") { params := map[string]interface{}{} for k, v := range request.Params { params[k] = toString(v) } data, err = e.tapiCall(request.Method[6:], params, "GET") } else if request.Method == "io" { // 扩展期货交易所对象需要的函数 code := toString(request.Params["code"]) if code == "0" { // 处理SetMarginLevel // ... } else if code == "1" { // 处理SetDirection // ... } else if code == "2" { // 处理SetContractType // ... } else if code == "3" { // 处理GetPosition // ... } else { panic(errors.New(request.Method + " not support")) } } else { panic(errors.New(request.Method + " not support")) } } if err != nil { panic(err) } ret = map[string]interface{}{ "data": data, } return }

SetMarginLevel/SetDirection/SetContractTypeDari arti harfiahnya, kita dapat melihat bahwa ketiga fungsi tersebut digunakan untuk mengatur konfigurasi yang relevan dari produk perdagangan saat ini. di dalamSetDirection/SetContractTypeDari perspektif desain, variabel lokal ditetapkan untuk mencatat arah pesanan saat ini (yaitu, saat melakukan pemesanan, pengaturan ini harus dibaca untuk mengetahui arah mana pesanan akan ditempatkan. Alasannya adalah pembelian berjangka memiliki dua arah : membuka posisi long dan menutup posisi short. Oleh karena itu, perlu dibedakan antara kode kontrak saat ini dan kode kontrak saat ini (kontrak mana yang sedang ditanyakan saat memperoleh informasi pasar, melakukan pemesanan, dll.).

SetMarginLevelPerlu dirancang secara khusus sesuai dengan mekanisme leverage bursa (1. Parameter leverage dilewatkan sebagai parameter dalam antarmuka pesanan. 2. Bursa memiliki antarmuka untuk menetapkan leverage).

GetPositionIni adalah fungsi untuk mendapatkan posisi produk saat ini. Ketika plug-in protokol umum mendapatkan data yang dikembalikan oleh antarmuka posisi pertukaran, plug-in tersebut secara langsung membangun fungsi posisi pada FMZ.positionStruktur data yang sama sudah cukup.

Contoh plug-in protokol umum berjangka AOFEX yang lengkap:

Pergi

mylang
/* CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build xxx.go */ package main import ( "bytes" "encoding/hex" "crypto/sha1" "encoding/json" "errors" "flag" "fmt" "io/ioutil" "log" "net/http" "net/url" "sort" "strconv" "strings" "time" // proxy "golang.org/x/net/proxy" "crypto/tls" "math/rand" ) var isUsedProxy bool = false var ct string = "" var direction string = "buy" var marginLevel float64 = 10 var currSymbol string = "" func toFloat(s interface{}) float64 { var ret float64 switch v := s.(type) { case float64: ret = v case float32: ret = float64(v) case int64: ret = float64(v) case int: ret = float64(v) case int32: ret = float64(v) case string: ret, _ = strconv.ParseFloat(strings.TrimSpace(v), 64) } return ret } func float2str(i float64) string { return strconv.FormatFloat(i, 'f', -1, 64) } func toInt64(s interface{}) int64 { var ret int64 switch v := s.(type) { case int: ret = int64(v) case float64: ret = int64(v) case bool: if v { ret = 1 } else { ret = 0 } case int64: ret = v case string: ret, _ = strconv.ParseInt(strings.TrimSpace(v), 10, 64) } return ret } func toString(s interface{}) string { var ret string switch v := s.(type) { case string: ret = v case int64: ret = strconv.FormatInt(v, 10) case float64: ret = strconv.FormatFloat(v, 'f', -1, 64) case bool: ret = strconv.FormatBool(v) default: ret = fmt.Sprintf("%v", s) } return ret } type Json struct { data interface{} } func NewJson(body []byte) (*Json, error) { j := new(Json) err := j.UnmarshalJSON(body) if err != nil { return nil, err } return j, nil } func (j *Json) UnmarshalJSON(p []byte) error { return json.Unmarshal(p, &j.data) } func (j *Json) Get(key string) *Json { m, err := j.Map() if err == nil { if val, ok := m[key]; ok { return &Json{val} } } return &Json{nil} } func (j *Json) CheckGet(key string) (*Json, bool) { m, err := j.Map() if err == nil { if val, ok := m[key]; ok { return &Json{val}, true } } return nil, false } func (j *Json) Map() (map[string]interface{}, error) { if m, ok := (j.data).(map[string]interface{}); ok { return m, nil } return nil, errors.New("type assertion to map[string]interface{} failed") } func (j *Json) Array() ([]interface{}, error) { if a, ok := (j.data).([]interface{}); ok { return a, nil } return nil, errors.New("type assertion to []interface{} failed") } func (j *Json) Bool() (bool, error) { if s, ok := (j.data).(bool); ok { return s, nil } return false, errors.New("type assertion to bool failed") } func (j *Json) String() (string, error) { if s, ok := (j.data).(string); ok { return s, nil } return "", errors.New("type assertion to string failed") } func (j *Json) Bytes() ([]byte, error) { if s, ok := (j.data).(string); ok { return []byte(s), nil } return nil, errors.New("type assertion to []byte failed") } func (j *Json) Int() (int, error) { if f, ok := (j.data).(float64); ok { return int(f), nil } return -1, errors.New("type assertion to float64 failed") } func (j *Json) MustArray(args ...[]interface{}) []interface{} { var def []interface{} switch len(args) { case 0: case 1: def = args[0] default: log.Panicf("MustArray() received too many arguments %d", len(args)) } a, err := j.Array() if err == nil { return a } return def } func (j *Json) MustMap(args ...map[string]interface{}) map[string]interface{} { var def map[string]interface{} switch len(args) { case 0: case 1: def = args[0] default: log.Panicf("MustMap() received too many arguments %d", len(args)) } a, err := j.Map() if err == nil { return a } return def } func (j *Json) MustString(args ...string) string { var def string switch len(args) { case 0: case 1: def = args[0] default: log.Panicf("MustString() received too many arguments %d", len(args)) } s, err := j.String() if err == nil { return s } return def } func (j *Json) MustInt64() int64 { var ret int64 var err error switch v := j.data.(type) { case int: ret = int64(v) case int64: ret = v case float64: ret = int64(v) case string: if ret, err = strconv.ParseInt(v, 10, 64); err != nil { panic(err) } default: ret = 0 } return ret } func (j *Json) MustFloat64() float64 { var ret float64 var err error switch v := j.data.(type) { case int: ret = float64(v) case int64: ret = float64(v) case float64: ret = v case string: v = strings.Replace(v, ",", "", -1) if ret, err = strconv.ParseFloat(v, 64); err != nil { panic(err) } default: ret = 0 } return ret } type headerTuple struct { name string value string } type Request struct { headers []headerTuple Proxy string Method string Uri string Body interface{} QueryString interface{} Timeout time.Duration ContentType string Accept string Host string UserAgent string } func (r *Request) AddHeader(name string, value string) { if r.headers == nil { r.headers = []headerTuple{} } r.headers = append(r.headers, headerTuple{name: name, value: value}) } type iAOFEX struct { accessKey string secretKey string clientID string currency string opCurrency string baseCurrency string quoteCurrency string apiBase string timeout time.Duration timeLocation *time.Location // ext contractTypes []string } type MapSorter []Item type Item struct { Key string Val string } func NewMapSorter(m map[string]string) MapSorter { ms := make(MapSorter, 0, len(m)) for k, v := range m { if strings.HasPrefix(k, "!") { k = strings.Replace(k, "!", "", -1) } ms = append(ms, Item{k, v}) } return ms } func (ms MapSorter) Len() int { return len(ms) } func (ms MapSorter) Less(i, j int) bool { return ms[i].Key < ms[j].Key } func (ms MapSorter) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] } func encodeParams(params map[string]string, escape bool) string { ms := NewMapSorter(params) sort.Sort(ms) v := url.Values{} for _, item := range ms { v.Add(item.Key, item.Val) } if escape { return v.Encode() } var buf bytes.Buffer keys := make([]string, 0, len(v)) for k := range v { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { vs := v[k] prefix := k + "=" for _, v := range vs { if buf.Len() > 0 { buf.WriteByte('&') } buf.WriteString(prefix) buf.WriteString(v) } } return buf.String() } func newiAOFEX(accessKey, secretKey string) *iAOFEX { s := new(iAOFEX) s.accessKey = accessKey s.secretKey = secretKey s.apiBase = "https://openapi-contract.aofex.info" s.timeout = 20 * time.Second s.timeLocation = time.FixedZone("Asia/Shanghai", 8*60*60) s.contractTypes = []string{"swap"} return s } func (p *iAOFEX) isValidContractType(contractType string) bool { for _, t := range p.contractTypes { if contractType == t { return true } } return false } func (p *iAOFEX) calcContractTypeMap(currency string) (contractTypeMap map[string]string, err error) { var baseCurrency, quoteCurrency string contractTypeMap = map[string]string{} if arr := strings.SplitN(currency, "_", 2); len(arr) == 2 { baseCurrency = arr[0] quoteCurrency = arr[1] } else { err = errors.New("symbol error!") return } contractTypeMap["swap"] = fmt.Sprintf("%s-%s", strings.ToUpper(baseCurrency), strings.ToUpper(quoteCurrency)) return } func (p *iAOFEX) apiCall(method string) (*Json, error) { req, err := http.NewRequest("GET", fmt.Sprintf("%s%s", p.apiBase, method), nil) if err != nil { return nil, err } fmt.Printf("\n %c[1;44;32m%s%c[0m\n", 0x1B, "apiCall GET create req:" + fmt.Sprintf("%s%s", p.apiBase, method), 0x1B) fmt.Println("req:", req) req.Header.Set("Content-Type", "application/json;utf-8") // proxy strProxy := "" client := http.DefaultClient if isUsedProxy { var auth *proxy.Auth proxyAddr := strings.Split(strProxy, "//")[1] if strings.Contains(proxyAddr, "@") { arr := strings.SplitN(proxyAddr, "@", 2) arrAuth := strings.SplitN(arr[0], ":", 2) proxyAddr = arr[1] auth = &proxy.Auth{} auth.User = arrAuth[0] if len(arrAuth) == 2 { auth.Password = arrAuth[1] } } var dialer proxy.Dialer if dialer, err = proxy.SOCKS5("tcp", proxyAddr, auth, proxy.Direct); err == nil { client = &http.Client{ Transport: &http.Transport{ Dial: dialer.Dial, MaxIdleConnsPerHost: 5, TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, ResponseHeaderTimeout: 20 * time.Second, }, Timeout: 20 * time.Second, } } else { return nil, err } } resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() b, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } var js *Json js, err = NewJson(b) if err != nil { return nil, err } // fault tolerant if _, ok := js.data.(map[string]interface{}); ok { if code, ok := js.MustMap()["code"]; ok { if toString(code) != "0" { err = errors.New(fmt.Sprintf("%v", js.data)) } } } return js, err } func (p *iAOFEX) GetTicker(symbol string) (ticker interface{}, err error) { mpCt, mpCtErr := p.calcContractTypeMap(symbol) if mpCtErr != nil { err = mpCtErr return } realCt, ok := mpCt[ct] if !ok { err = errors.New("invalid contractType!") return } var js *Json js, err = p.apiCall(fmt.Sprintf("/openApi/contract/market?symbol=%s", realCt)) if err != nil { return } depth, errDepth := p.GetDepth(symbol) if errDepth != nil { err = errDepth return } ask1 := depth.(map[string]interface{})["asks"].([][2]float64)[0][0] bid1 := depth.(map[string]interface{})["bids"].([][2]float64)[0][0] mp := js.Get("result").MustMap() ticker = map[string]interface{}{ "time": time.Now().UnixNano() / 1e6, "buy": toFloat(bid1), "sell": toFloat(ask1), "last": toFloat(mp["close"]), "high": toFloat(mp["high"]), "low": toFloat(mp["low"]), "vol": toFloat(mp["vol"]), } return } func (p *iAOFEX) GetDepth(symbol string) (depth interface{}, err error) { mpCt, mpCtErr := p.calcContractTypeMap(symbol) if mpCtErr != nil { err = mpCtErr return } realCt, ok := mpCt[ct] if !ok { err = errors.New("invalid contractType!") return } var js *Json js, err = p.apiCall(fmt.Sprintf("/openApi/contract/depth?symbol=%s", realCt)) if err != nil { return } asks := [][2]float64{} bids := [][2]float64{} for _, pair := range js.Get("result").Get("asks").MustArray() { arr := pair.([]interface{}) asks = append(asks, [2]float64{toFloat(arr[0]), toFloat(arr[1])}) } for _, pair := range js.Get("result").Get("bids").MustArray() { arr := pair.([]interface{}) bids = append(bids, [2]float64{toFloat(arr[0]), toFloat(arr[1])}) } depth = map[string]interface{}{ "time": js.Get("result").Get("ts").MustInt64(), "asks": asks, "bids": bids, } return } func (p *iAOFEX) GetTrades(symbol string) (trades interface{}, err error) { mpCt, mpCtErr := p.calcContractTypeMap(symbol) if mpCtErr != nil { err = mpCtErr return } realCt, ok := mpCt[ct] if !ok { err = errors.New("invalid contractType!") return } var js *Json js, err = p.apiCall(fmt.Sprintf("/openApi/contract/trade?symbol=%s", realCt)) if err != nil { return } items := []map[string]interface{}{} for _, pair := range js.Get("result").Get("data").MustArray() { item := map[string]interface{}{} mp := pair.(map[string]interface{}) item["id"] = toString(mp["id"]) item["price"] = toFloat(mp["price"]) item["amount"] = toFloat(mp["amount"]) item["time"] = toInt64(mp["ts"]) if toString(mp["direction"]) == "buy" { item["type"] = "buy" } else { item["type"] = "sell" } items = append(items, item) } for i := 0; i < len(items); i++ { for j := 0; j < len(items)-i-1; j++ { if toInt64(items[j]["time"]) > toInt64(items[j+1]["time"]) { items[j], items[j+1] = items[j+1], items[j] } } } trades = items return } func (p *iAOFEX) GetRecords(step int64, symbol string) (records interface{}, err error) { mpCt, mpCtErr := p.calcContractTypeMap(symbol) if mpCtErr != nil { err = mpCtErr return } realCt, ok := mpCt[ct] if !ok { err = errors.New("invalid contractType!") return } var periodDict map[int64]string = map[int64]string{ 1 : "1min", 5 : "5min", 15 : "15min", 30 : "30min", 60 : "1hour", 1440 : "1day", } period, okPeriod := periodDict[step] if !okPeriod { err = errors.New("period not support") return } var js *Json js, err = p.apiCall(fmt.Sprintf("/openApi/contract/kline?symbol=%s&period=%s&size=500", realCt, period)) if err != nil { return } items := []interface{}{} recordsData := js.Get("result").Get("data").MustArray() for i := len(recordsData) - 1 ; i >= 0 ; i-- { mp := recordsData[i].(map[string]interface{}) item := [6]interface{}{} item[0] = toInt64(mp["id"]) // time item[1] = toFloat(mp["open"]) // open item[2] = toFloat(mp["high"]) // high item[3] = toFloat(mp["low"]) // low item[4] = toFloat(mp["close"]) // close item[5] = toFloat(mp["vol"]) // vol items = append(items, item) } records = items return } func JSON_Encode(d interface{}) string { buffer := &bytes.Buffer{} encoder := json.NewEncoder(buffer) encoder.SetEscapeHTML(false) encoder.Encode(d) return buffer.String() } func (p *iAOFEX) tapiCall(httpMethod string, method string, params map[string]string) (js *Json, err error) { if params == nil { params = map[string]string{} } nonce := toString(time.Now().UnixNano() / 1e9) strLetter := "124567890abcdefghijklmnopqrstuvwxyz" for i := 0 ; i < 5 ; i++ { rand.Seed(time.Now().UnixNano()) nonce += string(strLetter[rand.Intn(len(strLetter))]) } arrParams := []string{} arrParams = append(arrParams, p.accessKey) arrParams = append(arrParams, p.secretKey) arrParams = append(arrParams, nonce) for k, v := range params { arrParams = append(arrParams, fmt.Sprintf("%s=%s", k, v)) } sort.Strings(arrParams) strSign := "" for _, ele := range arrParams { strSign += toString(ele) } h := sha1.New() h.Write([]byte(strSign)) signature := hex.EncodeToString(h.Sum(nil)) strUrl := fmt.Sprintf("%s%s", p.apiBase, method) if len(params) > 0 { strUrl = fmt.Sprintf("%s%s?%s", p.apiBase, method, encodeParams(params, false)) } req, err := http.NewRequest(httpMethod, strUrl, nil) if err != nil { return nil, err } req.Header.Add("Nonce", nonce) req.Header.Add("Token", p.accessKey) req.Header.Add("Signature", signature) strProxy := "" client := http.DefaultClient if isUsedProxy { var auth *proxy.Auth proxyAddr := strings.Split(strProxy, "//")[1] if strings.Contains(proxyAddr, "@") { arr := strings.SplitN(proxyAddr, "@", 2) arrAuth := strings.SplitN(arr[0], ":", 2) proxyAddr = arr[1] auth = &proxy.Auth{} auth.User = arrAuth[0] if len(arrAuth) == 2 { auth.Password = arrAuth[1] } } var dialer proxy.Dialer if dialer, err = proxy.SOCKS5("tcp", proxyAddr, auth, proxy.Direct); err == nil { client = &http.Client{ Transport: &http.Transport{ Dial: dialer.Dial, MaxIdleConnsPerHost: 5, TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, ResponseHeaderTimeout: 20 * time.Second, }, Timeout: 20 * time.Second, } } else { return nil, err } } fmt.Printf("\n %c[1;44;32m%s%c[0m\n", 0x1B, "apiCall GET create req:" + fmt.Sprintf("%s%s", p.apiBase, method), 0x1B) fmt.Println("tapiCall req:", req) resp, err := client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() b, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } js, err = NewJson(b) if err != nil { return nil, err } // fault tolerant if mp, ok := js.data.(map[string]interface{}); ok { if errno, ok := mp["errno"]; !ok || toString(errno) != "0" { err = errors.New(fmt.Sprintf("%v", js.data)) } } else { err = errors.New(fmt.Sprintf("%v", js.data)) } return js, err } func (p *iAOFEX) GetAccount(symbol string) (account interface{}, err error) { symbol = currSymbol mpCt, mpCtErr := p.calcContractTypeMap(symbol) if mpCtErr != nil { err = mpCtErr return } realCt, ok := mpCt[ct] if !ok { err = errors.New("invalid contractType!") return } var js *Json js, err = p.tapiCall("GET", "/openApi/contract/walletList", nil) if err != nil { return } assets := map[string]map[string]interface{}{} for _, ele := range js.Get("result").MustArray() { dic := ele.(map[string]interface{}) if realCt != toString(dic["symbol"]) { continue } arr := strings.SplitN(toString(dic["symbol"]), "-", 2) if arr[1] == "USDT" { if _, ok := assets[arr[1]]; !ok { assets[arr[1]] = map[string]interface{}{} } assets[arr[1]]["currency"] = arr[1] assets[arr[1]]["Info"] = dic assets[arr[1]]["free"] = toFloat(dic["avail"]) assets[arr[1]]["frozen"] = toFloat(dic["frozen"]) } } accounts := []map[string]interface{}{} for _, pair := range assets { accounts = append(accounts, pair) } account = accounts return } func (p *iAOFEX) Trade(side string, price, amount float64, symbol string) (orderId interface{}, err error) { mpCt, mpCtErr := p.calcContractTypeMap(symbol) if mpCtErr != nil { err = mpCtErr return } realCt, ok := mpCt[ct] if !ok { err = errors.New("invalid contractType!") return } params := map[string]string{} if direction == "buy" { params["contract_type"] = "open" } else if direction == "sell" { params["contract_type"] = "open" } else if direction == "closebuy" { params["contract_type"] = "close" } else if direction == "closesell" { params["contract_type"] = "close" } else { err = errors.New("invalid direction!") return } if (side == "buy-limit" || side == "buy-market") && (direction == "sell" || direction == "closebuy") { err = errors.New("invalid direction!") return } else if (side == "sell-limit" || side == "sell-market") && (direction == "buy" || direction == "closesell") { err = errors.New("invalid direction!") return } params["type"] = side params["lever_rate"] = toString(marginLevel) params["amount"] = toString(amount) params["symbol"] = realCt if price > 0 { params["price"] = toString(price) } var js *Json js, err = p.tapiCall("POST", "/openApi/contract/add", params) if err != nil { return } orderId = map[string]string{"id": toString(js.MustMap()["result"])} return } func (p *iAOFEX) GetOrders(symbol string) (orders interface{}, err error) { mpCt, mpCtErr := p.calcContractTypeMap(symbol) if mpCtErr != nil { err = mpCtErr return } realCt, ok := mpCt[ct] if !ok { err = errors.New("invalid contractType!") return } from := "" limit := 100 items := []map[string]interface{}{} for { params := map[string]string{ "symbol" : realCt, "limit" : toString(limit), } if from != "" { params["from"] = toString(from) } var js *Json js, err = p.tapiCall("GET", "/openApi/contract/currentList", params) if err != nil { return } arr := js.Get("result").MustArray() for _, ele := range arr { mp := ele.(map[string]interface{}) item := map[string]interface{}{} item["id"] = toString(mp["order_id"]) item["amount"] = toFloat(mp["amount"]) item["price"] = toFloat(mp["price"]) item["deal_amount"] = toFloat(mp["deal_amount"]) item["avg_price"] = toFloat(mp["price_avg"]) if toString(mp["type"]) == "buy-limit" || toString(mp["type"]) == "buy-market" || toString(mp["type"]) == "buy-tactics" || toString(mp["type"]) == "buy-market-tactic" || toString(mp["type"]) == "buy-plan" || toString(mp["type"]) == "buy-market-plan" { item["type"] = "buy" } else { item["type"] = "sell" } item["status"] = "open" item["contract_type"] = ct items = append(items, item) from = toString(mp["order_id"]) } if len(arr) < limit { break } } return items, nil } func (p *iAOFEX) GetOrder(orderId string, symbol string) (order interface{}, err error) { mpCt, mpCtErr := p.calcContractTypeMap(symbol) if mpCtErr != nil { err = mpCtErr return } realCt, ok := mpCt[ct] if !ok { err = errors.New("invalid contractType!") return } var js *Json js, err = p.tapiCall("GET", "/openApi/contract/historyList", map[string]string{ "from" : toString(orderId), "symbol" : realCt, "limit" : "1", }) if err != nil { return } item := map[string]interface{}{} for _, ele := range js.Get("result").MustArray() { mp := ele.(map[string]interface{}) if realCt != toString(mp["symbol"]) || toString(mp["order_id"]) != toString(orderId) { continue } item["id"] = toString(mp["order_id"]) item["amount"] = toFloat(mp["amount"]) item["price"] = toFloat(mp["price"]) item["deal_amount"] = toFloat(mp["deal_amount"]) item["avg_price"] = toFloat(mp["price_avg"]) item["contract_type"] = ct if toString(mp["type"]) == "buy-limit" || toString(mp["type"]) == "buy-market" || toString(mp["type"]) == "buy-tactics" || toString(mp["type"]) == "buy-market-tactic" || toString(mp["type"]) == "buy-plan" || toString(mp["type"]) == "buy-market-plan" { item["type"] = "buy" } else { item["type"] = "sell" } switch toString(mp["status"]) { case "1", "2": item["status"] = "open" case "3": item["status"] = "closed" case "4", "5", "6": item["status"] = "cancelled" } return item, nil } err = errors.New("order not found") return } func (p *iAOFEX) CancelOrder(orderId string, symbol string) (ret bool, err error) { mpCt, mpCtErr := p.calcContractTypeMap(symbol) if mpCtErr != nil { err = mpCtErr return } realCt, ok := mpCt[ct] if !ok { err = errors.New("invalid contractType!") return } _, err = p.tapiCall("POST", "/openApi/contract/cancel", map[string]string{ "order_ids" : toString(orderId), "symbol" : realCt, }) if err != nil { return } ret = true return } type RpcRequest struct { AccessKey string `json:"access_key"` SecretKey string `json:"secret_key"` Nonce int64 `json:"nonce"` Method string `json:"method"` Params map[string]interface{} `json:"params"` } func OnPost(w http.ResponseWriter, r *http.Request) { var ret interface{} defer func() { if e := recover(); e != nil { if ee, ok := e.(error); ok { e = ee.Error() } ret = map[string]string{"error": fmt.Sprintf("%v", e)} } b, _ := json.Marshal(ret) w.Write(b) }() b, err := ioutil.ReadAll(r.Body) if err != nil { panic(err) } var request RpcRequest err = json.Unmarshal(b, &request) if err != nil { panic(err) } e := newiAOFEX(request.AccessKey, request.SecretKey) symbol := strings.ToUpper(toString(request.Params["symbol"])) if _, ok := request.Params["symbol"]; ok { currSymbol = symbol } var data interface{} switch request.Method { case "ticker": data, err = e.GetTicker(symbol) case "depth": data, err = e.GetDepth(symbol) case "trades": data, err = e.GetTrades(symbol) case "records": data, err = e.GetRecords(toInt64(request.Params["period"]), symbol) case "accounts": data, err = e.GetAccount(symbol) case "trade": side := toString(request.Params["type"]) if side == "buy" { side = "buy-limit" if toFloat(request.Params["price"]) <= 0 { side = "buy-market" } } else { side = "sell-limit" if toFloat(request.Params["price"]) <= 0 { side = "sell-market" } } price := toFloat(request.Params["price"]) amount := toFloat(request.Params["amount"]) data, err = e.Trade(side, price, amount, symbol) case "orders": data, err = e.GetOrders(symbol) case "order": data, err = e.GetOrder(toString(request.Params["id"]), symbol) case "cancel": data, err = e.CancelOrder(toString(request.Params["id"]), symbol) default: if strings.HasPrefix(request.Method, "__api_") { params := map[string]string{} for k, v := range request.Params { params[k] = toString(v) } data, err = e.tapiCall("GET", request.Method[6:], params) } else if request.Method == "io" { code := toString(request.Params["code"]) if code == "0" { if args, ok := request.Params["args"].([]interface{}); ok && len(args) == 1 { marginLevel = toFloat(args[0]) } else { err = errors.New(fmt.Sprintf("%v", request.Params)) } } else if code == "1" { if args, ok := request.Params["args"].([]interface{}); ok && len(args) == 1 { orderDirection := toString(args[0]) if orderDirection == "buy" || orderDirection == "sell" || orderDirection == "closebuy" || orderDirection == "closesell" { direction = orderDirection data = orderDirection } else { err = errors.New(fmt.Sprintf("not support orderDirection: %s", orderDirection)) } } else { err = errors.New(fmt.Sprintf("%v", request.Params)) } } else if code == "2" { if args, ok := request.Params["args"].([]interface{}); ok && len(args) == 1 { contractType := toString(args[0]) if e.isValidContractType(contractType) { ct = contractType data = contractType } else { err = errors.New(fmt.Sprintf("not support contractType: %s", contractType)) } } else { err = errors.New(fmt.Sprintf("%v", request.Params)) } } else if code == "3" { symbol := currSymbol mpCt, mpCtErr := e.calcContractTypeMap(symbol) if mpCtErr != nil { panic(mpCtErr) } realCt, ok := mpCt[ct] if !ok { err = errors.New("invalid contractType!") panic(err) } var js *Json js, err = e.tapiCall("GET", "/openApi/contract/position", map[string]string{ "symbol" : realCt, }) if err != nil { panic(err) } items := []map[string]interface{}{} for _, ele := range js.Get("result").MustArray() { mp := ele.(map[string]interface{}) item := map[string]interface{}{} item["MarginLevel"] = toFloat(mp["lever_rate"]) item["Amount"] = toFloat(mp["amount"]) item["FrozenAmount"] = toFloat(mp["contract_frozen"]) item["Price"] = toFloat(mp["open_price_avg"]) item["Profit"] = toFloat(mp["un_profit"]) if toString(mp["type"]) == "1" { item["Type"] = 0 } else { item["Type"] = 1 } item["ContractType"] = ct item["Margin"] = toFloat(mp["bood"]) items = append(items, item) } data = items } else { panic(errors.New(request.Method + " not support")) } } else { panic(errors.New(request.Method + " not support")) } } if err != nil { panic(err) } ret = map[string]interface{}{ "data": data, } return } func main() { var addr = flag.String("b", "127.0.0.1:6617", "bind addr") flag.Parse() if *addr == "" { flag.Usage() return } basePath := "/AOFEX" log.Println("Running ", fmt.Sprintf("http://%s%s", *addr, basePath), "...") http.HandleFunc(basePath, OnPost) http.ListenAndServe(*addr, nil) }
Related Recommendations
Comment
All comments (2)

    麻了,这也太难了

    4 years ago

    找个程序员,2天就帮你搞定了。

    4 years ago
  • 1
iPhone Download
Forums
PINE Language
© 2015 - ∞ INVENTOR PTE LTD (SG)