FMZ 퀀트 플랫폼 전략 작성에 대한 고급 튜토리얼

저자:니나바다스, 창작: 2022-03-22 09:00:57, 업데이트: 2022-03-29 10:02:52

[TOC] 이 튜토리얼을 배우기 전에, 당신은 공부해야합니다FMZ 퀀트 플랫폼을 시작하세요그리고FMZ 퀀트 플랫폼 전략 작성 기본 튜토리얼, 그리고 프로그래밍 언어에 능숙해집니다.기본 튜토리얼은 가장 일반적으로 사용되는 함수를 다루지만, 도입되지 않은 많은 함수와 기능이 있으며, 이 튜토리얼에서는 다루지 않을 것입니다. FMZ 플랫폼에서 API 문서를 탐색하여 직접 이해할 필요가 있습니다.이 튜토리얼을 배운 후, 당신은 더 많은 무료 및 사용자 정의 전략을 쓸 수 있습니다. FMZ 퀀트 플랫폼은 단지 도구입니다.

플랫폼 원료 데이터에 액세스

FMZ 퀀트 플랫폼은 지원되는 모든 플랫폼을 포괄합니다. 통일성을 유지하기 위해 단일 플랫폼 API에 대한 지원은 아직 완전하지 않습니다. 예를 들어, GetRecords는 FMZ 플랫폼에 고정되는 동안 K-라인 수 또는 시작 시간을 전달할 수 있습니다. 일부 플랫폼은 팩 주문을 지원하지만 FMZ는 지원하지 않습니다. 따라서 플랫폼 데이터에 직접 액세스 할 수있는 방법이 필요합니다.공개 인터페이스 (시장 코팅 등) 를 위해,HttpQuery, 그리고 암호화된 인터페이스 (계정 정보 포함) 에 대해서는IO.특정 입력 매개 변수를 위해, 해당 플랫폼 API 문서를 참조하십시오. 이전 튜토리얼은Info이 필드는 원료를 반환하지만, 여전히 인터페이스를 지원하지 않는 문제에 대한 차이가 없습니다.

GetRawJSON ((()

그것은 마지막 REST API가 요청한 원시 콘텐츠 (strings) 를 반환하고 확장된 정보를 스스로 분석하는 데 사용할 수 있습니다.

function main(){
    var account = exchange.GetAccount() //the account doesn't contain all data returned by the request
    var raw = JSON.parse(exchange.GetRawJSON())//raw data returned by GetAccount()
    Log(raw)
}

HttpQuery() 공개 인터페이스에 액세스

공개 인터페이스에 액세스하려면, Js를 사용할 수 있습니다HttpQuery, 그리고 파이썬은 관련 패키지를 사용할 수 있습니다.urllib또는requests.

HttpQuery는 GET 메소드로 기본 설정되어 더 많은 기능을 지원합니다. 자세한 내용은 API 문서를 참조하십시오.

var exchangeInfo = JSON.parse(HttpQuery('https://api.binance.com/api/v1/exchangeInfo'))
Log(exchangeInfo)
var ticker = JSON.parse(HttpQuery('https://api.binance.com/api/v1/ticker/24hr'))
var kline = JSON.parse(HttpQuery("https://www.quantinfo.com/API/m/chart/history?symbol=BTC_USD_BITFINEX&resolution=60&from=1525622626&to=1561607596"))

요청을 사용하는 파이썬의 예제:

import requests
resp = requests.get('https://www.quantinfo.com/API/m/chart/history?symbol=BTC_USD_BITFINEX&resolution=60&from=1525622626&to=1561607596')
data = resp.json()

암호화된 인터페이스에 접근하는 IO

API-KEY 서명을 필요로 하는 인터페이스의 경우 IO 함수를 사용할 수 있으며, 사용자는 입력된 매개 변수에만 신경 쓸 필요가 있으며, 특정 서명이 하층에 의해 완료됩니다.

FMZ 플랫폼은 현재 BitMEX 스톱 로스 오더를 지원하지 않으며 IO를 통해 다음과 같은 단계에 따라 구현 할 수 있습니다.

  • 먼저, BitMEX API의 지침 페이지를 찾으세요:https://www.bitmex.com/api/explorer/;
  • 그럼 BitMEX의 주문 주소를 찾아보세요:https://www.bitmex.com/api/v1/order,POST; FMZ가 이미 내부적으로 기본 주소를 지정한 경우, 당신은 단지 /api/v1/order을 입력해야 합니다.
  • 해당 매개 변수symbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=Stop.

특정 코드:

var id = exchange.IO("api", "POST", "/api/v1/order", "symbol=XBTUSD&side=Buy&orderQty=1&stopPx=4000&ordType=Stop")
// You can also pass in the object 
var id = exchange.IO("api", "POST", "/api/v1/order", "", JSON.stringify({symbol:"XBTUSD",side:"Buy",orderQty:1,stopPx:4000,ordType:"Stop"}))

더 많은 IO 예제:https://www.fmz.com/bbs-topic/3683

웹소켓을 사용함

기본적으로 모든 암호화폐 플랫폼은 시장 코트를 전송하기 위해 웹소켓을 지원하고, 일부 플랫폼은 계정 정보를 업데이트하기 위해 웹소켓을 지원합니다. 휴식 API와 비교하면 웹소켓은 일반적으로 낮은 지연, 높은 주파수 및 플랫폼 휴식 API의 주파수 등에 의해 제한되지 않는 장점이 있습니다. 단점은 중단 문제가 있다는 것입니다. 그 처리가 직관적이지 않습니다.

이 문서에서는 주로 자바스크립트 언어를 사용하는 방법과 FMZ 퀀트 플랫폼에서 연결하기 위해 플랫폼에 의해 캡슐화 된 다이얼 함수를 사용하는 방법을 소개합니다. 특정 지침과 매개 변수는 문서에 있습니다. 다이얼을 검색 할 수 있습니다. 다양한 기능을 구현하기 위해 다이얼 함수는 여러 번 업데이트되었습니다. 이 문서에서는 wss를 기반으로 한 이벤트 기반 전략을 다루고 여러 플랫폼을 연결하는 문제를 소개합니다. 파이썬은 다이얼 함수 또는 해당 라이브러리를 사용할 수도 있습니다.

1. 웹소켓 연결

일반적으로, 웹소켓을 통해 직접 연결; 예를 들어, Binance 트리커 푸스를 얻기 위해:

var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr")

복귀된 데이터가 압축된 형식이라면 연결할 때 사양을 지정해야 합니다. compress은 압축된 형식을 의미하며, mode은 복귀된 데이터가 압축되어야 하는 것을 나타냅니다. 예를 들어, OKEX로 연결할 때:

var client = Dial("wss://real.okex.com:10441/websocket?compress=true|compress=gzip_raw&mode=recv")

다이얼 함수는 기본 골랑에 의해 수행되는 재연결을 지원합니다. 감지 된 연결이 끊어지면 재연결됩니다. 지금 바이낸스의 예시와 같은 url에 이미있는 요청 데이터에 대해서는 매우 편리하고 권장됩니다. 구독 메시지를 보내야하는 사람들은 재연결 메커니즘을 스스로 유지할 수 있습니다.

var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr|reconnect=true")

wss 메시지에 가입하려면 일부 플랫폼 요청이 url에 있으며 일부는 원본 채널 자체를 보내야합니다.

client = Dial("wss://ws-feed.pro.coinbase.com", 60)
client.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')

암호화된 인터페이스 연결

일반적으로 웹소켓은 시장 코트를 읽기 위해 사용되지만 주문 및 계정 푸시를 얻기 위해도 사용할 수 있습니다. 이러한 암호화 된 데이터의 푸시는 때때로 긴 지연을 가지고 있으므로 신중하게 사용해야합니다. 암호화 방법이 더 복잡하기 때문에 몇 가지 예를 참조로 제공합니다. 전략 매개 변수로 설정 할 수있는 AccessKey 만이 필요하다는 점에 유의하십시오. SecretKey가 필요한 경우 보안을 보장하기 위해 교환.HMAC() 함수로 암묵적으로 호출 할 수 있습니다.

    //Push example of Huobi Futures
    var ACCESSKEYID = 'accesskey of your Huobi account'
    var apiClient = Dial('wss://api.hbdm.com/notification|compress=gzip&mode=recv')
    var date = new Date(); 
    var now_utc =  Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(),date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
    var utc_date = new Date(now_utc)
    var Timestamp = utc_date.toISOString().substring(0,19)
    var quest = 'GET\napi.hbdm.com\n/notification\n'+'AccessKeyId='+ACCESSKEYID+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=' + encodeURIComponent(Timestamp)
    var signature = exchange.HMAC("sha256", "base64", quest, "{{secretkey} }") // Remove the extra blank spaces between }}
    auth = {op: "auth",type: "api",AccessKeyId: ACCESSKEYID, SignatureMethod: "HmacSHA256",SignatureVersion: "2", Timestamp: Timestamp, Signature:encodeURI(signature)}
    apiClient.write(JSON.stringify(auth))
    apiClient.write('{"op": "sub","cid": "orders","topic": "orders.btc'}')
    while (true){
        var data = datastream.read()
        if('op' in data && data.op == 'ping'){
            apiClient.write(JSON.stringify({op:'pong', ts:data.ts}))
        }
    }
    
    // Push example of Binance; pay attention that listenKey needs to be updated regularly   
    var APIKEY = 'accesskey of your Binance account'
    var req = HttpQuery('https://api.binance.com/api/v3/userDataStream',{method: 'POST',data: ''},null,'X-MBX-APIKEY:'+APIKEY);
    var listenKey = JSON.parse(req).listenKey;
    HttpQuery('https://api.binance.com/api/v3/userDataStream', {method:'DELETE',data:'listenKey='+listenKey}, null,'X-MBX-APIKEY:'+APIKEY);
    listenKey = JSON.parse(HttpQuery('https://api.binance.com/api/v3/userDataStream','',null,'X-MBX-APIKEY:'+APIKEY)).listenKey;
    var datastream = Dial("wss://stream.binance.com:9443/ws/"+listenKey+'|reconnect=true',60);
    var update_listenKey_time =  Date.now()/1000;
    while (true){
        if (Date.now()/1000 - update_listenKey_time > 1800){
            update_listenKey_time = Date.now()/1000;
            HttpQuery('https://api.binance.com/api/v3/userDataStream', {method:'PUT',data:'listenKey='+listenKey}, null,'X-MBX-APIKEY:'+APIKEY);
        }
        var data = datastream.read()
    }

    // push example of BitMEX
    var APIKEY = "your Bitmex API ID"
    var expires = parseInt(Date.now() / 1000) + 10
    var signature = exchange.HMAC("sha256", "hex", "GET/realtime" + expires, "{{secretkey} }")// secretkey is automatically replaced during execution, so no need to fill in
    var client = Dial("wss://www.bitmex.com/realtime", 60)
    var auth = JSON.stringify({args: [APIKEY, expires, signature], op: "authKeyExpires"})
    var pos = 0
    client.write(auth)
    client.write('{"op": "subscribe", "args": "position"}')
    while (true) {
        bitmexData = client.read()
        if(bitmexData.table == 'position' && pos != parseInt(bitmexData.data[0].currentQty)){
            Log('position change', pos, parseInt(bitmexData.data[0].currentQty), '@')
            pos = parseInt(bitmexData.data[0].currentQty)
        }
    }

3. 웹소켓 읽기

일반적으로, 그것은 무한한 루프에서 지속적으로 읽을 수 있습니다. 코드는 다음과 같습니다:

function main() {
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
    while (true) {
        var msg = client.read()
        var data = JSON.parse(msg) // Parse json strings into quotable objects 
// Process data 
    }
}

wss 데이터 푸시 속도는 매우 빠르다. 골랑의 하층은 대기열의 모든 데이터를 캐시하고, 프로그램 호출이 읽힐 때 데이터가 차례로 반환됩니다. 그러나 봇에 주문을 하는 것과 같은 작업은 지연을 유발할 수 있으며, 이로 인해 데이터가 축적 될 수 있습니다. 거래 실행 푸시, 계정 푸시 및 깊이 인터폴레이션 푸시와 같은 정보에 대해서는 역사 데이터가 필요합니다. 코트 시장 데이터에 대해서는 대부분의 경우 최신 데이터에 대해만 신경쓰고 역사 데이터가 아닙니다.

만약read()매개 변수를 추가하지 않으면 가장 오래된 데이터를 반환하고 데이터가 없을 때 반환할 때까지 차단합니다. 최신 데이터를 원한다면,client.read(-2)최신 데이터를 즉시 반환하지만 데이터가 없을 때 null을 반환합니다. 참조 전에 판단해야 합니다.

오래된 캐시된 데이터를 처리하는 방법과 데이터가 없을 때 차단되는지에 따라, read은 아래 표에서 보이는 바와 같이 다른 매개 변수를 가지고 있습니다. 이것은 복잡해 보이지만 프로그램을 더 유연하게 만듭니다.img

4. 웹소켓을 통해 여러 플랫폼과 연결

이 경우 단순히 read() 을 사용하는 것이 프로그램에서 작동하지 않는 것이 분명합니다. 한 플랫폼은 대기 메시지를 차단하고 다른 플랫폼은 새로운 메시지가있는 경우에도 수신하지 않을 것이기 때문입니다. 일반적인 처리 방법은:

    function main() {
        var binance = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
        var coinbase = Dial("wss://ws-feed.pro.coinbase.com", 60)
        coinbase.write('{"type": "subscribe","product_ids": ["BTC-USD"],"channels": ["ticker","heartbeat"]}')
        while (true) {
            var msgBinance = binance.read(-1) // Parameter -1 represents no data and return null immediately; it will not occur that being blocked before there is data to be returned 
            var msgCoinbase = coinbase.read(-1)
            if(msgBinance){
                // at this time, Binance has data to return 
            }
            if(msgCoinbase){
                // at this time, coinbase has data to return 
            }
            Sleep(1) // Sleep for 1 millisecond
        }
    }

5.절절 및 재연결 문제

이 부분은 푸시 데이터가 중단되거나 푸시 지연이 매우 길기 때문에 더 번거롭습니다. 심장 박동이 수신 될 수 있다고 하더라도 데이터가 여전히 푸시되고 있음을 의미하지는 않습니다. 이벤트 간격을 설정할 수 있습니다. 간격이 끝나면 업데이트가 수신되지 않으면 다시 연결하십시오. 데이터가 정확하는지 확인하기 위해 기간 후에 rest에 의해 반환된 결과를 비교하는 것이 좋습니다. 바이낸스의 특별한 경우 자동 재연결을 직접 설정할 수 있습니다.

6.웹소켓의 일반 프로그램 프레임 사용

푸시 데이터가 사용되었기 때문에 프로그램은 자연스럽게 이벤트 트리거로 작성됩니다. 높은 빈도의 요청이 차단 될 것이기 때문에 푸시 데이터의 주파수에주의를 기울일 수 있습니다. 일반적으로 다음과 같이 쓸 수 있습니다.

    var tradeTime = Date.now()
    var accountTime = Date.now()
    function trade(data){
        if(Date.now() - tradeTime > 2000){//Here it limits only one trade in 2 seconds 
            tradeTime = Date.now()
            // Trading logic
        }
    }
    function GetAccount(){
        if(Date.now() - accountTime > 5000){//Here it limits GetAccount only once in 5 seconds 
            accountTime = Date.now()
            return exchange.GetAccount()
        }
    }
    function main() {
        var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr|reconnect=true");
        while (true) {
            var msg = client.read()
            var data = JSON.parse(msg)
            var account = GetAccount()
            trade(data)
        }
    }

7.Conclusion

연결 방법, 데이터 전송 방법, 구독 된 콘텐츠 및 각 플랫폼의 웹소켓의 데이터 형식은 종종 다르기 때문에 플랫폼은 그것을 캡슐화하지 않으며 다이얼 기능을 사용하여 스스로 연결해야합니다. 이 기사는 기본적으로 몇 가지 기본적인 예방 조치를 다루고 있습니다. 더 많은 질문이 있으면 자유롭게 물어보십시오.

PS: 일부 플랫폼은 웹소켓 인용을 제공하지 않지만, 사실, 디버깅 기능을 사용하기 위해 웹 사이트에 로그인 할 때, 모든 웹소켓 푸시를 사용하고 있음을 알게 될 것입니다. 조사 한 후, 일부 구독 형식과 반환 형식이 암호화 된 것처럼 보이지만 base64로 디코딩 및 압축을 통해 볼 수 있습니다.

멀티 스레드 동행성

자바스크립트는 Go 함수에 의해 동결을 실현할 수 있고 파이썬은 해당 멀티 스레드 라이브러리를 사용할 수 있습니다.

양적 전략의 실현 동안, 동시 실행은 시간 지연을 줄이고 효율성을 향상시킬 수 있습니다. 예를 들어 헤지 전략 봇을 예로 들 수 있습니다. 두 동전의 깊이를 얻어야하며 순서대로 실행되는 코드는 다음과 같습니다.

var depthA = exchanges[0].GetDepth()
var depthB = exchanges[1].GetDepth()

휴식 API 요청이 지연되면, 예를 들어 지연 시간은 100 밀리 초입니다. 두 번 깊이 얻는 시간은 실제로 다릅니다. 더 많은 액세스가 필요하다면 지연 문제가 더 분명해지며 전략 실행에 영향을 줄 것입니다.

자바스크립트에는 멀티 스레드가 없기 때문에 하층은 이 문제를 해결하기 위해 Go 함수를 캡슐화합니다.GetDepth, GetAccount그리고 그 밖의 것들이죠.IO또한 지원됩니다. 예를 들어:exchange.Go("IO", "api", "POST", "/api/v1/contract_batchorder", "orders_data=" + JSON.stringify(orders))하지만 설계 메커니즘 때문에 구현하기가 더 지루합니다.

var a = exchanges[0].Go("GetDepth")
var b = exchanges[1].Go("GetDepth")
var depthA = a.wait() // Call "wait" method to wait for the return of the asynchronous GetDepth result 
var depthB = b.wait()

대부분의 간단한 경우, 이 방법으로 전략을 작성하는 것은 괜찮습니다. 그러나 전략 루프가 반복될 때마다 프로세스가 반복되고, 중간 변수 a와 b가 실제로 일시적으로 보조적인 것일 뿐이라는 점에 유의하십시오. 많은 동시 작업이 있다면, 우리는 추가적으로 a와 depthA, b와 depthB 사이의 대응을 기록해야 합니다. 우리의 동시 작업이 불확실할 때 상황은 더 복잡합니다. 따라서 우리는 함수를 실현하기를 희망합니다: Go 함수를 동시에 작성할 때, 동시에 변수를 묶어; 동시 실행 결과가 반환되면 결과 값은 자동으로 변수에 할당되며, 따라서 중간 변수와 프로그램을 더 간결하게 할 필요성을 제거합니다. 구체적인 구현은 다음과 같습니다:

function G(t, ctx, f) {
    return {run:function(){
        f(t.wait(1000), ctx)
    }}
}

우리는 G 함수를 정의했는데, 그 매개 변수 t은 실행될 Go 함수이고, ctx은 프로그램 컨텍스트 기록 함수이고, f은 특정 값을 부여하는 함수입니다. 이 함수의 효과를 나중에 보실 수 있습니다.

이 시점에서 전체 프로그램 프레임워크는 모델로 작성될 수 있으며, 제작자-소비자 모델과 비슷하다 (일부 차이점과 함께), 생산자는 지속적으로 작업을 전송하고 소비자는 동시에 작업을 수행한다. 다음 코드는 시범용으로만 제공되며 프로그램 실행 논리를 포함하지 않는다.

var Info = [{depth:null, account:null}, {depth:null, account:null}] // If we need to obtain the depth and account of the two platforms, more information can also be put in, such as order ID and status, etc.
var tasks = [ ] // Global task list 

function produce(){ // Issue all kinds of concurrent tasks
  // Here the task producing logic has been omitted, only for demo
  tasks.push({exchange:0, ret:'depth', param:['GetDepth']})
  tasks.push({exchange:1, ret:'depth', param:['GetDepth']})
  tasks.push({exchange:0, ret:'sellID', param:['Buy', Info[0].depth.Asks[0].Price, 10]})
  tasks.push({exchange:1, ret:'buyID', param:['Sell', Info[1].depth.Bids[0].Price, 10]})
}
function worker(){
    var jobs = []
    for(var i=0;i<tasks.length;i++){
        var task = tasks[i]
        jobs.push(G(exchanges[task.exchange].Go.apply(this, task.param), task, function(v, task) {
                    Info[task.exchange][task.ret] = v // Here "v" is the return value of the concurrent Go function "wait()", and you can think about it 
                }))
    }
    _.each(jobs, function(t){
            t.run() // Here all tasks are executed concurrently 
        })
    tasks = []
}
function main() {
    while(true){
        produce()         // Give trading command
        worker()        // Concurrently execute
        Sleep(1000)
    }
}

위의 작업에 간단한 함수만 구현된 것 같습니다. 사실, 그것은 코드의 복잡성을 크게 단순화했습니다. 우리는 프로그램이 생성해야 할 작업에 대해만 신경 쓸 필요가 있으며, worker))) 프로그램은 자동으로 동시에 실행하고 해당 결과를 반환합니다. 유연성은 많이 향상되었습니다.

차트 기능에 의한 그림

기본 튜토리얼에서, 그림의 소개에서 그림 클래스 라이브러리가 권장되며, 대부분의 경우 필요를 충족시킬 수 있습니다. 추가 사용자 정의가 필요한 경우, 차트 객체를 직접 조작할 수 있습니다.

내부 매개 변수Chart({…})HighStock와 HighCharts의 객체이지만 추가 매개 변수입니다__isStockFMZ는 기본적으로 HighCharts와 HighStock의 기본 모듈을 지원하지만 추가 모듈을 지원하지 않습니다. FMZ는 FMZ의 기본 모듈을 지원합니다.

특정 HighCharts 예제:https://www.highcharts.com/demoHighStock 예제:https://www.highcharts.com/stock/demo이 예제에서 코드를 참조하여 FMZ에 편리하게 이식할 수 있습니다.

지정된 인덱스를 가진 시리즈에 데이터를 추가하기 위해 추가 ([시리즈 인덱스 ((like 0), data]) 를 호출할 수 있습니다. 차트 데이터를 정리하기 위해 재설정 (reset) 을 호출하십시오. 재설정 (reset) 은 숫자 매개 변수를 취하고 저장해야 할 금액을 지정할 수 있습니다. 구성 중에 배열 매개 변수 (parameters) 에 전달해야 할 수 있는 여러 차트 표시가 지원됩니다. 예를 들어, 차트1가 두 시리즈를 가지고 있다면 차트2는 하나의 시리즈를 가지고 있으며, 차트3는 하나의 시리즈를 가지고 있습니다. 추가를 호출할 때, 시리즈 ID 0 및 1은 업데이트 된 차트1의 두 시리즈의 데이터를 별도로 나타내기 위해 지정됩니다. 시리즈 ID 2는 차트2의 첫 번째 시리즈의 데이터를 나타내기 위해 지정됩니다. 시리즈 ID 3는 차트3의 첫 번째 시리즈의 데이터를 나타내기 위해 지정됩니다.

구체적인 예시:

var chart = { // This "chart" in JS is an object; before using the Chart function, we need to declare the object variable of a configured chart "chart" 
    __isStock: true,                                    // Mark whether it is a general chart; you can change it to false and try to operate it, if you are interested 
    tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'},    // Zoom tool
    title : { text : 'spread chart'},                       // Theme
    rangeSelector: {                                    // Choose the range
        buttons:  [{type: 'hour',count: 1, text: '1h'}, {type: 'hour',count: 3, text: '3h'}, {type: 'hour', count: 8, text: '8h'}, {type: 'all',text: 'All'}],
        selected: 0,
        inputEnabled: false
    },
    xAxis: { type: 'datetime'},                         // Horizontal axis, namely X axis; currently set type: time
    yAxis : {                                           // Vertical axis, namely Y axis; the default changes according to the data 
        title: {text: 'spread'},                           // Theme
        opposite: false,                                // whether to enable the vertical axis on the right 
    },
    series : [                                          // Data series; the attribute saves all kinds of data series (lines, K-lines, labels, etc.)
        {name : "line1", id : "line1,buy1Price", data : []},  // The index is 0; the data stroed in the data array is the data of the index series 
        {name : "line2", id : "line2,lastPrice", dashStyle : 'shortdash', data : []}, // The index is 1; set  dashStyle: 'shortdash', namely: set  dashed line
    ]
};
function main(){
    var ObjChart = Chart(chart);  // Call the Chart function, and initialize the chart 
    ObjChart.reset();             // Empty 
    while(true){
        var nowTime = new Date().getTime();   // Obtain the timestamp of this polling, namely a millisecond tiemstamp, to ensure the location of writing to the X axis in the chart 
        var ticker = _C(exchange.GetTicker);  // Obtain the market quotes data
        var buy1Price = ticker.Buy;           // Get buy one price from the return value of the market quotes 
        var lastPrice = ticker.Last + 1;      // Get the final executed price, and we add 1 to split the 2 lines 
        ObjChart.add([0, [nowTime, buy1Price]]); // Use the timestamp as the value of X, and buy one price as the value of Y; pass in the data series of index 0  
        ObjChart.add([1, [nowTime, lastPrice]]); // Same as above. 
        Sleep(2000);
    }
}

차트 레이아웃을 사용하는 예제:https://www.fmz.com/strategy/136056

고급 백테스트

파이썬 로컬 백테스트

특정 오픈 소스 주소:https://github.com/fmzquant/backtest_python

설치

다음 명령어를 명령 줄에 입력합니다:

pip install https://github.com/fmzquant/backtest_python/archive/master.zip

단순 한 예

백테스트 매개 변수를 전략 코드의 시작에 댓글 형태로 설정하면 자세한 내용은 FMZ 웹 사이트의 전략 편집 페이지의 세팅 저장 버튼에서 표시됩니다.

'''backtest
start: 2018-02-19 00:00:00
end: 2018-03-22 12:00:00
period: 15m
exchanges: [{"eid":"OKEX","currency":"LTC_BTC","balance":3,"stocks":0}]
'''
from fmz import *
task = VCtx(__doc__) # initialize backtest engine from __doc__
print exchange.GetAccount()
print exchange.GetTicker()
print task.Join() # print backtest result

백테스트

완전한 전략은 무한한 루프가 필요하기 때문에 EOF 오류는 백테스트가 끝나면 증가합니다. 따라서 우리는 오류 관용을 잘해야 합니다.

# !/usr/local/bin/python
# -*- coding: UTF-8 -*-

'''backtest
start: 2018-02-19 00:00:00
end: 2018-03-22 12:00:00
period: 15m
exchanges: [{"eid":"Bitfinex","currency":"BTC_USD","balance":10000,"stocks":3}]
'''

from fmz import *
import math
import talib

task = VCtx(__doc__) # initialize backtest engine from __doc__

# ------------------------------ Start of the Strategy  --------------------------

print exchange.GetAccount()     # Call some interfaces, and print their return values 
print exchange.GetTicker()

def adjustFloat(v):             # the custom functions in the strategy 
    v = math.floor(v * 1000)
    return v / 1000

def onTick():
    Log("onTick")
    # Specific strategy code 


def main():
    InitAccount = GetAccount()
    while True:
        onTick()
        Sleep(1000)

# ------------------------------ End of the Strategy --------------------------

try:
    main()                     # The end of the backtest will raise EOFError() to stop stop the backtest loop. Therefore, we should handle with the error, and call task.Join() to print the backtest result, after the error is detected  
except:
    print task.Join()         

사용자 지정 백테스트 데이터

exchange.SetData(arr) 는 백테스트 데이터 소스를 전환하고 사용자 정의 K-라인 데이터를 사용합니다. 매개 변수 arr은 배열이며, 그 요소는 K-라인 바 데이터 (즉: K-라인 데이터 배열, 일시적으로 자바스크립트 백테스트만 지원합니다.

arr 배열에서 단일 요소의 데이터 형식:

[
    1530460800,    // time     Timestamp 
    2841.5795,     // open     Open Price 
    2845.6801,     // high     Highest Price
    2756.815,      // low      Lowest Price
    2775.557,      // close    Close Price
    137035034      // volume   Executed Volume 
]

데이터 소스는 템플릿으로 가져오면 됩니다.

function init() {                                                          // The init function in the template will be executed first when the template is loaded; ensure the exchange.SetData(arr) function is executed first, initialized, and set the data to the backtest system
    var arr = [                                                            // The K-line data to be used during backtest
        [1530460800,2841.5795,2845.6801,2756.815,2775.557,137035034],      // The data of the earliest K-line bar
        ... ,                                                              // If the K-line data is too long, use "..." to represent the omitted data here
        [1542556800,2681.8988,2703.5116,2674.1781,2703.5116,231662827]     // The data of the latest K-line bar 
    ]
    exchange.SetData(arr)                                                  // Import the custom data mentioned above 
    Log("Import data successfully")
}

참고: 초기화 중에 사용자 지정 데이터를 먼저 가져오십시오 (즉, 데이터를 설정하기 위해 exchange.SetData 함수를 호출하십시오). 사용자 지정 K-라인 데이터 기간은 백테스트 페이지에서 설정된 하위 계층 K-라인 기간과 일치해야합니다. 즉: 사용자 지정 K-라인 데이터; K-라인의 시간은 1 분입니다. 따라서 백테스트에서 설정된 하위 계층 K-라인 기간도 1 분으로 설정해야합니다.

FMZ가 지원하지 않는 플랫폼을 사용

지원되지 않는 플랫폼의 API가 지원되는 플랫폼과 정확히 같다면, 기본 주소를 제외하면 지원되지 않는 플랫폼은 기본 주소를 전환하여 지원 될 수 있습니다. 구체적으로, 플랫폼을 추가 할 때 지원되는 플랫폼을 선택하지만 지원되지 않는 플랫폼의 API-KEY를 작성하고 IO를 사용하여 전략에서 기본 주소를 변경하십시오.

exchange.IO("base", "http://api.huobi.pro") 
//http://api.huobi.pro is the base address of the unsupported platform API, and notice not to add api/v3 and so on, for the address will be automatically completed

모든 플랫폼이 FMZ에 의해 지원되는 것은 아니지만 우리의 플랫폼은 일반적인 프로토콜의 액세스 방법을 제공했습니다. 구체적인 원칙은:

  • 플랫폼에 접근하기 위해 코드를 작성하면 프로그램이 웹 서비스를 만듭니다.
  • FMZ에 플랫폼을 추가할 때, 웹 서비스의 주소와 포트를 지정합니다.
  • 도커가 일반 프로토콜의 플랫폼 봇을 실행할 때 전략의 API 액세스 요청은 일반 프로토콜에 전송됩니다.
  • 일반 프로토콜은 요청에 의해 플랫폼에 액세스하고 도커에 결과를 반환합니다.

간단히 말해서, 일반 프로토콜은 닷커의 요청을 프록시하고 해당 표준에 따라 데이터를 반환하는 중개자와 같습니다. 일반 프로토콜의 코드는 직접 완료해야합니다. 일반 프로토콜을 작성하는 것은 실제로 플랫폼에만 액세스하고 전략을 완료 할 수 있음을 의미합니다. FMZ 공식은 때때로 플랫폼의 일반 프로토콜의 exe 버전을 출시합니다. 일반 프로토콜은 파이썬에서도 수행 할 수 있으며, 일반 봇으로 닷커에서 실행 할 수 있습니다.

일반 프로토콜의 구체적인 도입:https://www.fmz.com/bbs-topic/9120파이썬에서 일반 프로토콜을 작성하는 예제:https://www.fmz.com/strategy/101399

자신만의 양적 플랫폼을 만드는 것

플랫폼의 다양한 동작이 API를 통해 구현될 수 있듯이 FMZ 웹사이트도 API를 기반으로 합니다. 당신은 create, restart, DeleteRobot, GetRobotList GetRobotLogs 등 기능을 구현하기 위해 FMZ 웹사이트의 자신의 API-KEY를 신청할 수 있습니다. 자세한 내용은 API 문서의 API 확장 프로그램 FMZ 플랫폼 섹션을 참조하십시오.

FMZ 퀀트 플랫폼의 강력한 확장성으로 인해 API 확장 프로그램을 기반으로 자신의 양적 플랫폼을 만들 수 있으며 사용자가 플랫폼에서 봇을 실행할 수 있습니다.https://www.fmz.com/bbs-topic/1697 .

FMZ의 파트너가 되는 방법

네트 이즈 교실 홍보

암호화폐 거래 시장은 그 특수성으로 인해 양적 거래자로부터 점점 더 많은 관심을 끌고 있습니다. 실제로, 프로그램 거래는 암호화폐의 주류가 되었고, 헤지 및 시장 제작과 같은 전략은 항상 시장에서 활발합니다. 약한 프로그래밍 기반을 가진 초보자들은 많은 플랫폼과 변화하는 API와 대면하여 많은 어려움으로 가득 차있는이 새로운 분야에 진출하고자합니다. FMZ 양자 플랫폼, (옛 BotVs,www.fmz.com현재 가장 큰 암호화폐 양적 커뮤니티 및 플랫폼으로, 4년 이상 수 천 명의 초보자들이 양적 거래의 길을 걷도록 도와 왔습니다.

홍보넷 이즈 클라우드 클래스 룸에서 암호화폐 양적 거래 과정. 넷 이즈 클라우드 클래스 룸에 로그인하여 코스 링크를 공유하십시오. 다른 사람들은 이 링크를 통해 등록하고 코스를 구매하면 전체의 50%를 수수료로, 즉 10 위안으로 가져옵니다. 현금을 인출하기 위해 넷 이즈 클라우드 클래스 룸 프리미엄 코스 프로모션의 WeChat 공개 계정을 따르십시오. 당신은 또한 웨이보 또는 QQ 그룹에서 코스를 홍보하도록 다른 사람들을 초대 할 수 있습니다.

제휴

프로모션 링크를 클릭하고 등록하고 반년 이내에 충전하는 소비자는 당사의 회사가 유효한 순서에서 유효한 금액에 따라 할인하는 정책을 즐길 수 있습니다. 수수료는 포인트 형태로 프로모터 계정에 반환됩니다. 사용자는 FMZ 플랫폼의 계좌 잔액에 점수를 10:1 비율로 교환 할 수 있으며 사용자는 또한 점수를 사용하여 미래에 FMZ 퀀트의 관련 제품을 교환 할 수 있습니다. 활동에 대한 특정 링크:https://www.fmz.com/bbs-topic/3828

기업을 위한 FMZ 퀀트 플랫폼

전체 FMZ 웹 사이트는 완전한 제어 및 기능적 사용자 정의를 위해 기업 또는 팀의 독점 서버에 배포 할 수 있습니다. FMZ 웹 사이트는 약 10만 명의 사용자가 사용하고 테스트했으며 양적 팀과 기업에 시간을 절약 할 수있는 높은 가용성과 보안을 달성했습니다. 엔터프라이즈 버전은 중간 규모의 양적 거래 팀, 상품 선물 서비스 제공자 등을위한 것입니다. 구체적인 코팅을 위해 관리자에게 문의하십시오.

시장 제작 시스템

플랫폼에 대한 시장 유동성 및 자금 관리를 제공하는 전문 시스템은 시장에서 가장 개선 된 시장 제작 시스템 일 수 있습니다. 많은 플랫폼과 팀에서 널리 사용됩니다.

플랫폼 계획

FMZ 기술 거래 시스템은 메모리 매칭 기술을 채택하고 있으며, 주문 처리 속도는 초당 200만 거래에 달하며, 주문 처리에는 지연이나 지연이 없도록 보장 할 수 있습니다. 동시 온라인 사용자 2천만 명 이상의 플랫폼의 원활하고 안정적인 운영을 유지할 수 있습니다. 다층 및 다클러스터 시스템 프레임워크는 시스템의 보안, 안정성 및 확장성을 보장합니다. 기능 배포 및 버전 업데이트는 다운타임없이 수행 할 수 있으며, 이는 터미널 사용자의 운영 경험을 최대한 보장합니다. 현재 시스템은 wex.app 시뮬레이션 플랫폼에서 경험 할 수 있습니다.


더 많은