発明者 量化取引プラットフォーム 汎用プロトコル 独自の取引所へのアクセス

作者: リン・ハーン小さな夢作成日:2017年8月24日 16:29:56 更新日:2021年6月10日 15:33:02

汎用プロトコルの使用文書

この通用プロトコルのいずれかにアクセスできます.API取引の取引所,特定のAPIプロトコルの制限はありません.restwebsocketfixメディアは,インターネットの利用者を対象としています. Pythonの一般的なプロトコルの例:https://www.fmz.com/strategy/101399

  • 1 汎用プロトコルのプラグインを実行,ポート設定

    盗聴アドレスとポート設定を書き込みます. 例えば:http://127.0.0.1:6666/DigitalAssetメディアは,http://127.0.0.1:6666/exchange

    なぜこれを設定するのか?IP経路ほら 原因は発明者の量化ページコントロールセンタージャンプエクスチェンジを追加ページをクリックすると, "General Protocol" を選択します.API-KEYサービスアドレスのアドレスは,ホストがどのIPとポートにアクセスすべきかを伝える (ホストとUPRは同じデバイスで実行できない) サービスアドレスの例を記入します.http://127.0.0.1:6666/DigitalAssetDigitalAssetこの名前は自明な名前ですが,例として挙げます.

    発明者による量化追加取引所のページは,以下のように見えます. 通常,取引所では,アカウントの設定情報を設定するだけです.access keyそしてsecret keyしかし,一部の取引所のAPIインターフェイスは取引パスワードを伝達することを要求する (例えば,一部の取引所の下記のインターフェイス),このとき,通用プロトコルページに余分なコントロールが書き込まれるので,そのような取引所のAPIに出くわしたとき,余分な伝達が必要な設定情報を書き込むことができます.secret keyメールの送信は,メールの送信先に表示されます.access key文字列を書き換えるには,split図示のように,このデータを分離する操作をします.

    img

    プラグインで処理し,それを取得します.XXX_PassWord│ │ この記事の最後の完全な例では,newBitgoの関数は,

    func newBitgo(accessKey, secretKey string) *iBitgo {
        s := new(iBitgo)
        s.accessKey = accessKey
        s.secretKey = secretKey
        // 在此可以分离secretKey中的额外配置信息,可以写成如下注释中的内容
        /*
        arr := strings.SplitN(secretKey, ",", 2)
        if len(arr) != 2 {
            panic("配置错误!")
        }
        s.secretKey = arr[0]   // secret key 
        s.passWord = arr[1]    // XXX_PassWord
        */
        s.apiBase = "https://www.bitgo.cn"
        s.timeout = 20 * time.Second
        s.timeLocation = time.FixedZone("Asia/Shanghai", 8*60*60)
    
        return s
    }
    

    img

    汎用プロトコルプラグインmain函数の例:Go言語の説明:

    func main(){
        var addr = flag.String("b", "127.0.0.1:6666", "bing addr")   // 设置命令行参数,默认值描述,端口设置6666
        flag.Parse()                                                 // 解析命令行
        if *addr == "" {
            flag.Usage()                                             // 显示命令行描述
            return 
        }
        basePath := "/DigitalAsset"
        log.Println("Running ", fmt.Sprintf("http://%s%s", *addr, basePath), "...")   // 打印监听端口信息
        http.HandleFunc(basePath, OnPost)
        http.ListenAndServe(*addr, nil)
    }
    
  • 2 応答関数

    一般プロトコルのプラグインを操作する パックプログラムは,指定されたポートを絶えず監視し,要求が送信されているか確認します.request■リクエストがあったら,応答関数を呼び出し,リクエストデータのパラメータを解析し,ホストが送信するリクエストデータは:

    /* request的JSON结构,发明者量化调用GetTicker,托管者发送给通用协议插件情况举例(各个API调用时,params的值可能不一样,此处method为ticker):
    {
        "access_key" : "XXX",               // `json:"access_key"`
        "secret_key" : "XXX",               // `json:"secret_key"`
        "nonce" : "1502345965295519602",    // `json:"nonce"`
        "method" : "ticker",                // `json:"method"`
        "params" : {                        // `json:"params"`
                       "symbol" : "btc",
                       ...
                   },                       // 各个请求参数略有区别。即在策略中调用不同的 发明者量化 API会有不同的参数, 在下文各个API 有介绍说明。
    }
    */
    

    JSONのデータに対する反シリアル化によって得られる構造です.request中身Methodコンピュータはswitch異なる発明者による量化処理を分類するAPI (つまり,ホスト上で実行されるポリシーを識別する呼び出しがどの発明者による量化であるかを識別する)API呼び出し:

    Go言語の例:

    switch request.Method {    // 此处request.Method的M为大写,通用协议程序接收到的请求主体中为JSON数据,在Go语言中反JSON序列化(Unmarshal)为结构体,字段首字母必须大写
      case "accounts" :        // 当托管者上的机器人策略中调用了exchange.GetAccount()函数,托管者会发送来请求,其中Body携带的数据中method属性值为accounts
          data, err = e.GetAccount(symbol)
      case "ticker" :
          data, err = e.GetTicker(symbol)
      case "depth" :
          data, err = e.GetDepth(symbol)
      case "trades" :
          data, err = e.GetTrades(symbol)
      case "trade" :
      ...
      default:
          ...
    

    これらのブランチは,実行後に返されるデータを,通用プロトコルプラグインが返答する構造に書き込み,托管者の要求に応答する.

    Go言語の例:

    defer func(){                                // 处理收尾工作 
          if e := recover(); e != nil {          // recover()函数用于捕获panic,e != nil即有错误发生
              if ee, ok := e.(error); ok {       // 类型推导,推导成功把ee.Error()赋值给e
                  e = ee.Error()                 // 调用Error方法获取返回的错误字符串
              }
              ret = map[string]string{"error": fmt.Sprintf("%v", e)}
          }
          b, _ := json.Marshal(ret)              // 把本次调用获取的结果ret编码,赋值给b,写入响应指针
          w.Write(b)
          //fmt.Println("after w.Write the b is", string(b))     // 测试
      }()
    
  • 3.APIの呼び出しの種類

    基本的には2つのカテゴリーに分かれます. 署名を必要としない公共インターフェース,例えば:

    GetTicker()

    GetDepth()

    GetTrades()

    GetRecords(period)

    2 署名が必要なユーザーインターフェース,例えば:

    BuySell

    GetOrder(id)

    GetOrders()

    GetAccount()

    CancelOrder(id)ありがとうございました. 取引所によって署名方法が異なることもあり,必要に応じて書き込む必要がある.

  • 4 発明者がAPIの呼び出しを量化する一般プロトコルプラグインそして管理者インタラクティブなデータ形式:

    発明者によって量化されたAPIはGetName()GetLabel()この関数は,等式関数で,一般プロトコルプラグインメールの送信は,exchange.GetName()一般プラグイン設定の取引所への呼び出しでは"Exchange"が返されます.

    • 1、ゲットティッカー:市場が動いていることを確認するために,

      管理者監視応答関数に送信します.request中身method理由:ticker

      パラメータを送信する管理者:request.Params.symbol管理者がボットページの設定に基づいて送る通貨.

      管理者が通用プロトコルプラグインに要求する際に主体によって運ばれるデータ形式 (JSON)

      {
          "access_key" : "access_key",
          "secret_key" : "secret_key",
          "nonce" :      "1500793319499",            // 毫秒时间戳
          "method" :     "ticker",
          "params" :     {"symbol" : "ETH_BTC"},     // 以ETH_BTC交易对举例
      }
      

      最終的に托管者に送信される返却値構造: (即ち,通用プロトコルプラグインが取引所のインターフェースを要求したデータが托管者に返されるフォーマット)

      JSON構造

      {
          "data": {
              "time": 1500793319499,  // 毫秒时间戳,整型
              "buy": 1000,            // 以下浮点型
              "sell": 1001,
              "last": 1005,
              "high": 1100,
              "low": 980,
              "vol": 523,
          }
      }
      
    • 2、GetRecords: 記録を入手する取引所が提供するK線データを取得する.

      監視応答機能に送信します.request中身method理由:records

      パラメータを送信する管理者:request.Params.period価値関連exchange.GetRecordsこの関数の最初のパラメータは,request.Params.period周期は数分で表される.例えば,日周期は60*24これは1440request.Params.symbol管理者は設定された通貨に基づいて送信します.

      管理者が通用プロトコルのプラグインに要求する際に主体によって運ばれるデータ形式

      {
          "access_key" : "access_key",
          "secret_key" : "secret_key",
          "nonce" :      "1500793319499",            // 毫秒时间戳
          "method" :     "records",
          "params" :     {"symbol" : "ETH_BTC", "period" : "1440"},     // 以ETH_BTC交易对,K线周期为日线举例
      }
      

      管理者へ送られる 返却値構造:

      JSON構造

      {
          "data": [
                  [1500793319, 1.1, 2.2, 3.3, 4.4, 5.5],         // "Time":1500793319000,"Open":1.1,"High":2.2,"Low":3.3,"Close":4.4,"Volume":5.5
                  [1500793259, 1.01, 2.02, 3.03, 4.04, 5.05],
                  ...
          ]
      }
      

      Go言語テストのデータ:

      ret_records = []interface{}{
          [6]interface{}{1500793319, 1.1, 2.2, 3.3, 4.4, 5.5}, 
          [6]interface{}{1500793259, 1.01, 2.02, 3.03, 4.04, 5.05}
      }
      

      発明者定量化プラットフォームLog表示するrecordsニュース

      [
          {"Time":1500793319000,"Open":1.1,"High":2.2,"Low":3.3,"Close":4.4,"Volume":5.5},
          {"Time":1500793259000,"Open":1.01,"High":2.02,"Low":3.03,"Close":4.04,"Volume":5.05}
      ]
      

      この式は,この式の2番目の要素です.int管理者は自動的に 1000 を掛ける時間を掛ける.

    • 3、深度を取得:取引所の詳細情報 (注文が薄い,1売り,2売り...1買,2買...)

      監視応答機能に送信します.request中身method理由:depth

      パラメータを送信する管理者:request.Params.symbol策定された通貨によって送られる:

      管理者が通用プロトコルのプラグインに要求する際に主体によって運ばれるデータ形式

      {
          "access_key" : "access_key",
          "secret_key" : "secret_key",
          "nonce" :      "1500793319499",            // 毫秒时间戳
          "method" :     "depth",
          "params" :     {"symbol" : "ETH_BTC"},     // 以ETH_BTC交易对举例
      }
      

      管理者への返却の価値構造:

      JSON構造

      {
          "data" : {
              "time" : 1500793319499,
              "asks" : [ [1000, 0.5], [1001, 0.23], [1004, 2.1], ... ],
              "bids" : [ [999, 0.25], [998, 0.8], [995, 1.4], ... ],
          }
      }
      
    • 4、GetTrades:取引所から提供される取引記録 (自社以外の取引記録) を,取引所全体で特定の時間間に取得する

      監視応答機能に送信します.request中身method理由:trades

      パラメータを送信する管理者:request.Params.symbol取引される通貨は,例えば:btc管理者が設定した通貨で送信します.

      管理者が通用プロトコルのプラグインに要求する際に主体によって運ばれるデータ形式

      {
          "access_key" : "access_key",
          "secret_key" : "secret_key",
          "nonce" :      "1500793319499",            // 毫秒时间戳
          "method" :     "trades",
          "params" :     {"symbol" : "ETH_BTC"},     // 以ETH_BTC交易对举例
      }
      

      管理者への返却の価値構造:

      JSON構造

      { 
          "data": [
              {
                  "id": 12232153,
                  "time" : 1529919412968,
                  "price": 1000,
                  "amount": 0.5,
                  "type": "buy",             // "buy"、"sell"
              },{
                  "id": 12545664,
                  "time" : 1529919412900,
                  "price": 1001,
                  "amount": 1,
                  "type": "sell",
              },{
                  ...
              }
          ]
      }
      
    • 5、GetAccount: アカウントを取得するアカウント資産情報を取得

      監視応答機能に送信します.request中身method理由:accounts

      托管者が送信するパラメータ: ((注意!一般的にはアカウントのすべての資産を取得する!,特に取引所のインターフェースを参照してください,個別に取得するか,総資産情報を取得する)

      管理者が通用プロトコルのプラグインに要求する際に主体によって運ばれるデータ形式

      {
          "access_key" : "access_key",
          "secret_key" : "secret_key",
          "nonce" :      "1500793319499",            // 毫秒时间戳
          "method" :     "accounts",
          "params" :     {},                         
      }
      

      管理者へ送られる 返却値構造:

      JSON構造

      {
          "data": [
              {"currency": "btc", "free": 1.2, "frozen": 0.1},
              {"currency": "ltc", "free": 25, "frozen": 2.1},
              {"currency": "ltc", "free": 25, "frozen": 2.1},
              ...
          ],
          "raw" : {...}             // 可以写入插件访问交易所时,交易所返回的原始信息(response)
      }
      
    • 6、買い、売る注文を送信し,取引を注文します.

      監視応答機能に送信します.request中身method理由:trade

      パラメータを送信する管理者:request.Params.type管理者:呼び出しによってexchange.Buyありがとうございましたexchange.Sell投稿者:request.Params.price戦略で呼び出す:APIこの関数の最初のパラメータはrequest.Params.amount戦略で呼び出す:APIこの関数の2番目のパラメータはrequest.Params.symbol管理者は設定された通貨に基づいて送信します.

      管理者が通用プロトコルのプラグインに要求する際に主体によって運ばれるデータ形式

      {
          "access_key" : "access_key",
          "secret_key" : "secret_key",
          "nonce" :      "1500793319499",            // 毫秒时间戳
          "method" :     "trade",
          "params" :     {
                             "symbol" : "ETH_BTC", 
                             "type" : "buy", 
                             "price" : "1000", 
                             "amount" : "1"
                         },                          // 以ETH_BTC交易对,"type":"buy"买请求,价格1000,数量1举例
      }
      

      管理者への返却の価値構造:

      JSON構造

      {
          "data": {
              "id": 125456,      // 下单后返回的订单id
                                 // 如果订单id是"asdf346sfasf532"这样的字符串形式
                                 // 此处id也可以是字符串类型
          }
      }
      
    • 7、Getオーダー:指定された注文番号の注文情報を取得します

      監視応答機能に送信します.request中身method理由:order

      パラメータを送信する管理者:request.Params.idrequest.Params.symbol

      管理者が通用プロトコルのプラグインに要求する際に主体によって運ばれるデータ形式

      {
          "access_key" : "access_key",
          "secret_key" : "secret_key",
          "nonce" :      "1500793319499",            // 毫秒时间戳
          "method" :     "order",
          "params" :     {"symbol" : "ETH_BTC", "id" : "XXX"},     // 以ETH_BTC交易对,订单id为XXX举例,注意有些交易所的订单号是数字形式的订单ID,如123456,有些交易所的订单号是字符串形式的ID,如poimd55sdfheqxv,具体看交易所的订单ID格式
      }
      

      管理者への返却の価値構造:

      JSON構造

      { 
          "data": {
              "id": 2565244,
              "amount": 0.15,
              "price": 1002,
              "status": "open",    // "open":挂起状态、"closed":完成关闭状态、"cancelled":已取消
              "deal_amount": 0,
              "type": "buy",       // "buy"、"sell"
              "avg_price": 0,      // 如果交易所没有提供,在处理时可以赋值为0
          }
      }
      
    • 8、Getオーダー:すべての未完成の注文情報を取得します.

      監視応答機能に送信します.request方法として,orders

      パラメータを送信する管理者:request.Params.symbol

      管理者が通用プロトコルのプラグインに要求する際に主体によって運ばれるデータ形式

      {
          "access_key" : "access_key",
          "secret_key" : "secret_key",
          "nonce" :      "1500793319499",            // 毫秒时间戳
          "method" :     "orders",
          "params" :     {"symbol" : "ETH_BTC"},     // 以ETH_BTC交易对举例
      }
      

      管理者への返却の価値構造:

      JSON構造

      {
          "data": [{
              "id": 542156,
              "amount": 0.25,
              "price": 1005,
              "deal_amount": 0,
              "type": "buy",      // "buy"、"sell"
              "status": "open",   // "open"
          },{
              ...
          }]
      }
      
    • 9、キャンセル注文:指定された注文番号の注文委託を取り消す

      監視応答機能に送信します.request中身method理由:cancel

      パラメータを送信する管理者:request.Params.id文字列の種類,ポリシーによるAPI関数の最初のパラメータ,request.Params.symbol:btc ((例) は,管理者が設定した通貨によって送信されます.

      管理者が通用プロトコルのプラグインに要求する際に主体によって運ばれるデータ形式

      {
          "access_key" : "access_key",
          "secret_key" : "secret_key",
          "nonce" :      "1500793319499",            // 毫秒时间戳
          "method" :     "cancel",
          "params" :     {"symbol" : "ETH_BTC", "id" : "XXX"},     // 以ETH_BTC交易对,id为"XXX"(同GetOrder函数的参数id一样),举例
      }
      

      管理者への返却の価値構造:

      JSON構造

      {
          "data": true,        // true or false
      }
      
    • 10、IO:调用发明者量化平台的exchange.IO函数

      監視応答機能に送信します.request中身methodありがとうございました.__api_方法の名前は,最初の文字で始まる.

      管理者が通用プロトコルのプラグインに要求する際に主体によって運ばれるデータ形式

      {
          "access_key" : "access_key",
          "secret_key" : "secret_key",
          "nonce" :      "1500793319499",            // 毫秒时间戳
          "method" :     "__api_XXX",                // XXX为具体交易所的API接口(不包含基地址)
          "params" :     {"borrow_id" : "123", "symbol" : "cny"},      // 具体是传入IO函数的参数
      }
      

      管理者への返却の価値構造:

      {
          "data": {...}       // 具体的接口调用的返回值
      }
      

      例えば,戦略呼び出しは:

      var io_str = exchange.IO("api", "POST", "cancel_borrow", "symbol=cny&borrow_id=123")
      

      プラグインのテストコード (go言語):

      fmt.Println("request.Method:", request.Method, "request.Params:", request.Params)
      

      プラグインのコマンドライン: 2017/08/31 10:19:59 ランニングhttp://127.0.0.1:6666/DigitalAsset

      プラグインのコマンドラインにプリントされた request.Method,request.Params管理者が送信したリクエストBodyのデータ解析後のリクエストには:request.Method理由:__api_cancel_borrow管理者が送信したリクエストBodyのデータ解析後のリクエストには:request.Params理由:{"borrow_id" : "123", "symbol" : "cny"}

      直接アクセスできる取引所の処理をカスタマイズできますAPIありがとうございました.exchange.IO呼び出しする.

      # 注意:
      # 在调用exchange.IO("api", "POST", "/api/v1/getAccount", "symbol=BTC_USDT")时,
      # 如果第二个参数不是POST,而是:exchange.IO("api", "GET", "/api/v1/getAccount", "symbol=BTC_USDT")
      # 是GET方法,这时在通用协议插件接受到的http请求中头部Http-Method中储存的才是GET,
      # 所以在通用协议处理IO函数实现时,需要参考以下范例代码:
      // tapiCall函数定义
      func (p *iStocksExchange) tapiCall(method string, params map[string]string, httpType string) (js *Json, err error) {
          ...
      }
      
      // 在OnPost函数中
      if strings.HasPrefix(request.Method, "__api_") {
          var js *Json
          js, err = e.tapiCall(request.Method[6:], request.Params, r.Header.Get("Http-Method"))
          ...
      }
      
    • 对于exchange.GetRawJSON的支持

      底辺の自動処理exchange.GetRawJSONプラグインで実装する必要はありません.

    • 对于exchange.Go的支持

      底辺の自動処理exchange.Goプラグインで処理する必要はありません.

      var beginTime = new Date().getTime()
      var ret = exchange.Go("GetDepth")
      var endTime = new Date().getTime()
      Log(endTime - beginTime, "#FF0000")
      
      // Sleep(2000)
      beginTime = new Date().getTime()
      Log(exchange.GetTicker())
      endTime = new Date().getTime()
      Log(endTime - beginTime, "#FF0000")
      var depth = ret.wait()
      Log("depth:", depth)
      

      img

      img

      # 注意:使用exchange.Go在wait的时候如果指定了超时时间, 
      #      一定要确保获取到最终的数据,这样申请的并发线程才能回收。
      
    • フューチャー関数のサポート

      プラグインで特定の処理を実装する必要があり,例えばレバレッジ,契約コード,下順位を設定し,ローカル変数レコードを設定し,保有を取得するには,取引所のインターフェースにアクセスし,原始データを取得し,FMZプラットフォームで定義された保有構造を処理し,戻す必要があります. プラグインは,次の関数を呼び出すときに,Rpcリクエスト形式は他のインターフェースとわずかに異なるため,通用プロトコルプラグインで注意する必要がありますRpcRequestParams の値が複合構造である.

      • SetContractType について
        契約コードを設定します.

        {"access_key":"123","method":"io","nonce":1623307269528738000,"params":{"args":["quarter"],"code":2},"secret_key":"123"}
        
      • 設定方向性 未来を"つの方向に設定します.

        {"access_key":"123","method":"io","nonce":1623308734966484000,"params":{"args":["closesell"],"code":1},"secret_key":"123"}
        
      • 設定する 未来レバレッジを設定する.

        {"access_key":"123","method":"io","nonce":1623308734966939000,"params":{"args":[12],"code":0},"secret_key":"123"}
        
      • 位置を表示する 将来の保有権を取得する. どこにいるのかexchange.GetPosition()呼び出し時:

        {"access_key":"123","method":"io","nonce":1623308734967442000,"params":{"args":[],"code":3},"secret_key":"123"}
        

        どこにいるのかexchange.GetPosition("swap")呼び出し時:

        {"access_key":"123","method":"io","nonce":1623308734967442000,"params":{"args":["swap"],"code":3},"secret_key":"123"}
        

  • 汎用プロトコルプラグインの完全なGo言語例 (ビットコイン取引所へのアクセス)

/*
GOOS=linux GOARCH=amd64 go build -ldflags '-s -w -extldflags -static' rest_bitgo.go
*/
package main

import (
    "bytes"
    "crypto/md5"
    "encoding/hex"
    "encoding/json"
    "errors"
    "flag"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "net/url"
    "sort"
    "strconv"
    "strings"
    "time"
)

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
        //panic("type assertion to int64 failed")
    }
    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
        //panic("type assertion to float64 failed")
    }
    return ret
}

type iBitgo struct {
    accessKey     string
    secretKey     string
    currency      string
    opCurrency    string
    baseCurrency  string
    secret        string
    secretExpires int64
    apiBase       string
    step          int64
    newRate       float64
    timeout       time.Duration
    timeLocation  *time.Location
}

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].Val < ms[j].Val // 按值排序
    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 newBitgo(accessKey, secretKey string) *iBitgo {
    s := new(iBitgo)
    s.accessKey = accessKey
    s.secretKey = secretKey
    s.apiBase = "https://www.bitgo.cn"
    s.timeout = 20 * time.Second
    s.timeLocation = time.FixedZone("Asia/Shanghai", 8*60*60)

    return s
}

func (p *iBitgo) apiCall(method string) (*Json, error) {
    req, err := http.NewRequest("POST", fmt.Sprintf("%s/appApi.html?%s", p.apiBase, method), nil)
    if err != nil {
        return nil, err
    }
    req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()
    b, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }
    return NewJson(b)
}

func (p *iBitgo) GetTicker(symbol string) (ticker interface{}, err error) {
    var js *Json
    js, err = p.apiCall("action=market&symbol=" + symbol)
    if err != nil {
        return
    }
    dic := js.Get("data")
    ticker = map[string]interface{}{
        "time": js.Get("time").MustInt64(),
        "buy":  dic.Get("buy").MustFloat64(),
        "sell": dic.Get("sell").MustFloat64(),
        "last": dic.Get("last").MustFloat64(),
        "high": dic.Get("high").MustFloat64(),
        "low":  dic.Get("low").MustFloat64(),
        "vol":  dic.Get("vol").MustFloat64(),
    }
    return
}

func (p *iBitgo) GetDepth(symbol string) (depth interface{}, err error) {
    var js *Json
    js, err = p.apiCall("action=depth&symbol=" + symbol)
    if err != nil {
        return
    }
    dic := js.Get("data")

    asks := [][2]float64{}
    bids := [][2]float64{}

    for _, pair := range dic.Get("asks").MustArray() {
        arr := pair.([]interface{})
        asks = append(asks, [2]float64{toFloat(arr[0]), toFloat(arr[1])})
    }

    for _, pair := range dic.Get("bids").MustArray() {
        arr := pair.([]interface{})
        bids = append(bids, [2]float64{toFloat(arr[0]), toFloat(arr[1])})
    }
    depth = map[string]interface{}{
        "time": js.Get("time").MustInt64(),
        "asks": asks,
        "bids": bids,
    }
    return
}

func (p *iBitgo) GetTrades(symbol string) (trades interface{}, err error) {
    var js *Json
    js, err = p.apiCall("action=trades&symbol=" + symbol)
    if err != nil {
        return
    }
    dic := js.Get("data")
    items := []map[string]interface{}{}
    for _, pair := range dic.MustArray() {
        item := map[string]interface{}{}
        arr := pair.(map[string]interface{})
        item["id"] = toInt64(arr["id"])
        item["price"] = toFloat(arr["price"])
        item["amount"] = toFloat(arr["amount"])
        // trade.Time = toInt64(arr["time"]) * 1000
        if toString(arr["en_type"]) == "bid" {
            item["type"] = "buy"
        } else {
            item["type"] = "sell"
        }
        items = append(items, item)
    }
    trades = items
    return
}

func (p *iBitgo) GetRecords(step int64, symbol string) (records interface{}, err error) {
    var js *Json
    js, err = p.apiCall(fmt.Sprintf("action=kline&symbol=%s&step=%d", symbol, step*60))
    if err != nil {
        return
    }
    items := []interface{}{}
    for _, pair := range js.Get("data").MustArray() {
        arr := pair.([]interface{})
        if len(arr) < 6 {
            err = errors.New("response format error")
            return
        }
        item := [6]interface{}{}
        item[0] = toInt64(arr[0])
        item[1] = toFloat(arr[1])
        item[2] = toFloat(arr[2])
        item[3] = toFloat(arr[3])
        item[4] = toFloat(arr[4])
        item[5] = toFloat(arr[5])

        items = append(items, item)
    }
    records = items
    return
}

func (p *iBitgo) tapiCall(method string, params map[string]string) (js *Json, err error) {
    if params == nil {
        params = map[string]string{}
    }
    params["api_key"] = p.accessKey
    h := md5.New()
    h.Write([]byte(encodeParams(params, false) + "&secret_key=" + p.secretKey))
    params["sign"] = strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
    params["action"] = method
    qs := encodeParams(params, false)

    req, err := http.NewRequest("POST", fmt.Sprintf("%s/appApi.html?%s", p.apiBase, qs), nil)
    if err != nil {
        return nil, err
    }
    req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
    resp, err := http.DefaultClient.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 js != nil {
        if code := js.Get("code").MustInt64(); code != 200 {
            s := js.Get("msg").MustString()
            if s == "" {
                s = fmt.Sprintf("%v", toString(js.data))
            }
            return nil, errors.New(s)
        }
    }
    return js, err
}

func (p *iBitgo) GetAccount(symbol string) (account interface{}, err error) {
    var js *Json
    js, err = p.tapiCall("userinfo", nil)
    if err != nil {
        return
    }
    mp := js.Get("data")
    assets := map[string]map[string]interface{}{}
    for k := range mp.MustMap() {
        dic := mp.Get(k)
        if k == "free" {
            for c := range dic.MustMap() {
                if _, ok := assets[c]; !ok {
                    assets[c] = map[string]interface{}{}
                }
                assets[c]["currency"] = c
                assets[c]["free"] = dic.Get(c).MustFloat64()
            }
        } else if k == "frozen" {
            for c := range dic.MustMap() {
                if _, ok := assets[c]; !ok {
                    assets[c] = map[string]interface{}{}
                }
                assets[c]["currency"] = c
                assets[c]["frozen"] = dic.Get(c).MustFloat64()
            }
        }
    }
    accounts := []map[string]interface{}{}
    for _, pair := range assets {
        accounts = append(accounts, pair)
    }

    account = accounts
    return
}

func (p *iBitgo) Trade(side string, price, amount float64, symbol string) (orderId interface{}, err error) {
    var js *Json
    js, err = p.tapiCall("trade", map[string]string{
        "symbol": symbol,
        "type":   side,
        "price":  float2str(price),
        "amount": float2str(amount),
    })
    if err != nil {
        return
    }
    orderId = map[string]int64{"id": js.Get("orderId").MustInt64()}
    return
}

func (p *iBitgo) GetOrders(symbol string) (orders interface{}, err error) {
    var js *Json
    js, err = p.tapiCall("entrust", map[string]string{"symbol": symbol})
    if err != nil {
        return
    }
    items := []map[string]interface{}{}
    for _, ele := range js.Get("data").MustArray() {
        mp := ele.(map[string]interface{})
        item := map[string]interface{}{}
        item["id"] = toInt64(mp["id"])
        item["amount"] = toFloat(mp["count"])
        if _, ok := mp["prize"]; ok {
            item["price"] = toFloat(mp["prize"])
        } else {
            item["price"] = toFloat(mp["price"])
        }
        item["deal_amount"] = toFloat(mp["success_count"])

        if toInt64(mp["type"]) == 0 {
            item["type"] = "buy"
        } else {
            item["type"] = "sell"
        }
        item["status"] = "open"
        items = append(items, item)
    }
    return items, nil
}

func (p *iBitgo) GetOrder(orderId int64, symbol string) (order interface{}, err error) {
    var js *Json
    js, err = p.tapiCall("order", map[string]string{"id": toString(orderId)})
    if err != nil {
        return
    }

    found := false
    item := map[string]interface{}{}
    for _, ele := range js.Get("data").MustArray() {
        mp := ele.(map[string]interface{})
        if toInt64(mp["id"]) != orderId {
            continue
        }
        item["id"] = toInt64(mp["id"])
        item["amount"] = toFloat(mp["count"])
        if _, ok := mp["prize"]; ok {
            item["price"] = toFloat(mp["prize"])
        } else {
            item["price"] = toFloat(mp["price"])
        }
        item["deal_amount"] = toFloat(mp["success_count"])

        if toInt64(mp["type"]) == 0 {
            item["type"] = "buy"
        } else {
            item["type"] = "sell"
        }
        switch toInt64(mp["status"]) {
        case 1, 2:
            item["status"] = "open"
        case 3:
            item["status"] = "closed"
        case 4:
            item["status"] = "cancelled"
        }
        found = true
        break
    }
    if !found {
        return nil, errors.New("order not found")
    }
    return item, nil
}

func (p *iBitgo) CancelOrder(orderId int64, symbol string) (ret bool, err error) {
    _, err = p.tapiCall("cancel_entrust", map[string]string{"id": strconv.FormatInt(orderId, 10)})
    if err != nil {
        return
    }
    ret = true
    return
}

type RpcRequest struct {        // 结构体里的字段首字母必须大写,否则无法正常解析,结构体有导出和未导出,大写字母开头为导出。
                                // 在Unmarshal的时候会  根据 json 匹配查找该结构体的tag, 所以此处需要修饰符
    AccessKey string            `json:"access_key"`
    SecretKey string            `json:"secret_key"`
    Nonce     int64             `json:"nonce"`
    Method    string            `json:"method"`
    Params    map[string]string `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 := newBitgo(request.AccessKey, request.SecretKey)
    symbol := request.Params["symbol"]
    if s := request.Params["access_key"]; len(s) > 0 {
        e.accessKey = s
    }
    if s := request.Params["secret_key"]; len(s) > 0 {
        e.secretKey = s
    }
    if symbolIdx, ok := map[string]int{
        "btc":  1,
        "ltc":  2,
        "etp":  3,
        "eth":  4,
        "etc":  5,
        "doge": 6,
        "bec":  7,
    }[strings.Replace(strings.ToLower(symbol), "_cny", "", -1)]; ok {
        symbol = toString(symbolIdx)
    }
    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 := request.Params["type"]
        if side == "buy" {
            side = "0"
        } else {
            side = "1"
        }
        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(toInt64(request.Params["id"]), symbol)
    case "cancel":
        data, err = e.CancelOrder(toInt64(request.Params["id"]), symbol)
    default:
        if strings.HasPrefix(request.Method, "__api_") {
            data, err = e.tapiCall(request.Method[6:], request.Params)
        } 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:6666", "bind addr")
    flag.Parse()
    if *addr == "" {
        flag.Usage()
        return
    }
    basePath := "/exchange"
    log.Println("Running ", fmt.Sprintf("http://%s%s", *addr, basePath), "...")
    http.HandleFunc(basePath, OnPost)
    http.ListenAndServe(*addr, nil)
}


もっと

小草パイトン接点プロトコルのカスタマイズされた取引所の例 https://www.fmz.com/strategy/101399

小草Python接点プロトコルのカスタマイズされた交換例https://www.fmz.com/strategy/101399

リウウイ9090bitmexの取引所はプラットフォームにアクセスしていますが, _C ((exchange.GetTicker).Buy とか _C ((exchange.GetDepth).Bids[0]はどちらも購入価格を得ることができず,エラーも返します.なぜかわかりません.

毎日 柔らかい模様ハーハ,GPLのプラグインを書けば,完全に交換APIを連結できるのか,それとも自分のプログラムで直接使うのか?

シュチ751ロボット/戦略/取引所の配置など,完全なプロトコルのアクセス例はありますか? 模倣以上の話,ハハハ

ほらこのコードは,UTPプラグインですよね? このプラグインは,私が直接呼び出すことができる策略模型のようなものではありませんか? 私はpy post またはgetを使って送信し,データを取得し,解析します. このUTPプラグインのコードは, botvsのAPIを受信し,それを解析し,監視アドレスとポートを設定する http://127.0.0.1:6666/DigitalAssetを書き,実際にはhttps://www.bitmex.com/のようなアドレスではありませんか?

シャリーPythonの場合は,これだけです.

ゼーディプラグインを使うことは,多くの関数を自分で書くことを意味するのか,例えばGetAccout (?

アランヤオbotVSはjsの例ではありませんか?なぜjsがないのか?なぜGOがあるのか?

nxtプレーヤー6号機が離陸したが,うまくいかない.

婚約者も野蛮な

小さな夢BITMEXはフューチャー取引所である. 操作または取得する契約を設定するには,APIのドキュメント exchange.SetContractType関数を参照してください.

毎日 柔らかい模様そして,

小さな夢しかし,もし戦略がマルチプラットフォームだったら? 森を1本の木のために捨てるわけにはいかない!

小さな夢実行可能なファイルにコンパイルし,管理者と一緒に実行できます. この記事へのトラックバック一覧です. Python の例はまだないので,時間を取って作ってみました.

ほらプラグインは,それを実行させる方法,例えばpy形式で書き,ホストexeディレクトリに直接置くか?また,ローカルpyプログラムでプラグインのpyファイルディレクトリに参照のパスを追加するか?

小さな夢ポリシーは特別な処理を必要とせず,BotVS apiのインターフェースでは,これらの取引所のオブジェクトは同じである (BotVSがアクセスされているか,またはあなたが自分で書いた通用プロトコルプラグインがサポートされているか),ポリシーは変更する必要はありません. このプラグインと管理者が一緒に動作します. 上記のドキュメントを参照してください: 1 汎用プロトコルプラグインを実行,ポート設定 この記事へのトラックバック一覧です.

ほらこの機能は,自分の書いた後,プラグインに対応する取引所がここに関数を呼び,他の取引所が既存のbotvs apiを使用する策略模型のようです.

小さな夢- この汎用プロトコルプラグインのコードは, botvsのAPIを接続しながら,post、get を解読し,実行しているのですか? - http://127.0.0.1:6666/DigitalAsset このアドレスは,取引所のオブジェクトを代表し,管理者の要求がこのアドレスに送られる.プラグインサービスプログラムは,このアドレス要求を監視し,応答し,管理者の代わりに取引所にアクセスし,管理者の要求されたデータを返します.

小さな夢Pythonで実装したものは同じです インターフェースやフォーマットも同じです 言語の違いだけです.

小さな夢この例は,ホストの外部プラグイン形式で,BotVSプラットフォームへのアクセスのためのいくつかの取引所のインタラクティブコードを書き出すことを目的としています. PHP,node.js,python,Goなどの言語でこのようなプラグインを書き出すことができます.

小さな夢はい,BotVS API GetAccountなどのインターフェース機能の具体的実装を書き出すことは,接続された取引所のコードを自分で書き込むことと同じです.

小さな夢Python,node.js,PHP,Golangなども使用できます.