리소스 로딩... 로딩...

FMZ 정량화 플랫폼 전략 작성 단계 교육

저자:초목, 2019-08-19 15:54:35, 업데이트: 2021-06-08 16:14:57

[TOC] 이 튜토리얼을 배우기 전에 먼저 배워야 합니다.FMZ 발명가 양적 플랫폼을 이용한 소개그리고FMZ 정량화 플랫폼 전략 작성 초등 교과서그리고 프로그래밍 언어를 능숙하게 사용합니다.초보 튜토리얼은 가장 많이 사용되는 함수를 다루지만, 많은 함수와 기능들이 소개되지 않고 있으며, 이 튜토리얼에서는 다루지 않을 것이며, 플랫폼 API 문서를 직접 살펴볼 필요가 있다.이 튜토리얼을 마친 후, 당신은 더 자유롭고, 더 맞춤형 전략을 쓸 수 있을 것입니다. FMZ 플랫폼은 단지 하나의 도구입니다.

거래소의 원본 데이터에 액세스하세요

FMZ 플랫폼은 지원되는 모든 거래소를 포괄하고 있으며, 통일성을 유지하기 위해 개별 거래소 API 지원이 완전하지 않습니다. 예를 들어, K 라인을 얻는 것은 일반적으로 K 라인의 수 또는 시작 시간에 전달 될 수 있지만 FMZ 플랫폼은 고정되어 있으며 일부 플랫폼은 대량 주문을 지원하고 FMZ는 지원하지 않습니다.공개된 인터페이스 (예: 시장) 에 사용할 수 있습니다.HttpQuery, 엑스페리어 (아카운트 정보 입력) 를 위해 사용해야 합니다.IO특정 입력 매개 변수는 해당 거래소 API 문서를 참조하십시오. 이전 튜토리얼에서 소개되었습니다.Info필드는 원래 정보를 반환하지만 여전히 인터페이스를 지원하지 않는 문제를 해결할 수 없습니다.

GetRawJSON ((()

마지막 REST API 요청에서 반환된 원본 컨텐츠 (string) 를 반환하여 자체적으로 확장 정보를 분석할 수 있습니다.

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 Stop Loss Order를 지원하지 않으며 다음과 같은 단계로 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")
//也可以直接传入对象
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

웹소켓 사용

기본적으로 모든 디지털 통화 거래소는 웹소켓 전송 시장을 지원하며 일부 거래소는 웹소켓 업데이트 계정 정보를 지원합니다. rest API와 비교하면 웹소켓은 일반적으로 지연이 낮고 빈도가 높으며 플랫폼 rest API의 빈도 제한이 없습니다.

이 문서는 주로 FMZ의 발명자 정량화 플랫폼, 자바스크립트 언어를 사용하는, 플랫폼에 포착된 다이얼 함수를 사용하는 연결, 문서에 설명 및 매개 변수를 사용하는, 다이얼을 검색하는, 다양한 기능을 구현하기 위해 다이얼 함수가 몇 번 업데이트 된 것을 다루고 있으며, 이 문서는 wss 기반의 이벤트 드라이브 전략을 소개하고, 여러 거래소를 연결하는 문제를 설명합니다. 파이썬은 다이얼 함수를 사용할 수 있으며, 해당 라이브러리를 사용할 수 있습니다.

1.websocket连接

일반적으로 직접 연결할 수 있습니다.

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

반환된 데이터는 압축된 형식으로, 연결이 필요한 경우 압축된 형식을 지정하고, mode는 연결된 OKEX와 같은 압축이 필요한 데이터를 전송하는 것을 나타냅니다.

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

다이얼 함수는 재결합을 지원하며, 기본 언어인 Go에서 수행되며, 검출된 연결이 끊어지고 재결합이 됩니다. 요청된 데이터의 내용이 이미 url에 있는 경우, 예를 들어, 위안의 경우, 매우 편리하며, 사용이 권장됩니다.

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

WSS 메시지를 구독하고, 일부 거래소의 요청은 url에 있으며, Coinbase와 같은 채널에서 직접 구독을 요청합니다:

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

2.加密接口连接

일반적으로 웹소켓을 사용하여 트랜잭션을 읽을 수 있지만, 주문, 계정 추진을 얻기 위해도 사용할 수 있습니다. 이러한 암호화 데이터의 추진은 때때로 상당한 지연을 초래할 수 있으므로 신중하게 사용해야합니다. 암호화 방법이 더 복잡하기 때문에 몇 가지 예를 참조하십시오.

    //火币期货推送例子
    var ACCESSKEYID = '你的火币账户的accesskey'
    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} }") //去掉}}之间的多余空格
    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}))
        }
    }
    
    //币安推送例子,注意需要定时更新listenKey
    var APIKEY = '你的币安accesskey'
    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()
    }

    //BitMEX推送例子
    var APIKEY = "你的Bitmex API ID"
    var expires = parseInt(Date.now() / 1000) + 10
    var signature = exchange.HMAC("sha256", "hex", "GET/realtime" + expires, "{{secretkey} }")//secretkey在执行时自动替换,不用填写
    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.websocket读取

일반적으로 사형 순환에서 계속 읽습니다. 코드는 다음과 같습니다:

function main() {
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
    while (true) {
        var msg = client.read()
        var data = JSON.parse(msg) //把json字符串解析为可引用的object
// 处理data数据
    }
}

wss 데이터 푸시는 매우 빠르며, Go의 하층은 모든 데이터를 대기열에 두어, 다른 프로그램이 READ를 호출할 때 순차적으로 반환합니다. 실제 디스크의 아래 목록과 같은 작업은 시간이 지연되어 데이터의 축적을 일으킬 수 있습니다. 거래 푸시, 계정 푸시, 깊이 인플러트 푸시와 같은 정보에는 역사적 데이터가 필요합니다. 시장 데이터에는 대부분의 경우 최신 데이터에 관심이 있습니다.

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

캐시된 오래된 데이터를 어떻게 처리하는지, 그리고 데이터가 없을 때 막히는지에 따라, read에는 다른 매개 변수가 있습니다.img

4.连接多个交易所websocket

이 경우의 절차는 명백히 단순한 read (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) // 参数-1代表无数据立即返回null,不会阻塞到有数据返回
            var msgCoinbase = coinbase.read(-1)
            if(msgBinance){
                // 此时币安有数据返回
            }
            if(msgCoinbase){
                // 此时coinbase有数据返回
            }
            Sleep(1) // 可以休眠1ms
        }
    }

5.断线重连问题

이 부분은 푸싱 데이터가 중단될 수도 있고, 또는 푸싱 지연이 매우 높기 때문에 처리하는 것이 더 번거롭다. 심장 박동을 수신해도 데이터가 여전히 푸싱되고 있음을 의미하지 않으며, 이벤트 간격을 설정할 수 있으며, 간격을 초과하면 업데이트가 수신되지 않으면 다시 연결할 수 있으며, 데이터의 정확성 여부를 확인하기 위해 시간이 걸리고 rest가 반환되는 결과를 비교하는 것이 좋습니다. 비안의 특별한 경우, 자동 재연결을 직접 설정할 수 있습니다.

6.使用websocket的一般程序框架

이미 푸싱 데이터가 사용되었기 때문에, 프로그램은 자연스럽게 이벤트 드라이버로 작성되기도 합니다. 데이터를 자주 푸싱하여 너무 많은 요청으로 인해 폐쇄되지 않도록 주의하십시오. 일반적으로 다음과 같이 작성할 수 있습니다.

    var tradeTime = Date.now()
    var accountTime = Date.now()
    function trade(data){
        if(Date.now() - tradeTime > 2000){//这里即限制了2s内只交易一次
            tradeTime = Date.now()
            //交易逻辑
        }
    }
    function GetAccount(){
        if(Date.now() - accountTime > 5000){//这里即限制了5s内只获取账户一次
            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.总结

각 거래소의 웹소켓의 연결 방식, 데이터 전송 방식, 구독 가능한 내용, 데이터 형식은 종종 다릅니다. 따라서 플랫폼은 포장이 없으며, 다이얼 기능을 사용하여 자동 연결이 필요합니다. 이 문서에서는 기본적으로 몇 가지 기본적인 주의 사항을 다루고 있습니다.

PS. 일부 거래소는 웹소켓 시장을 제공하지 않지만 실제로 로그인 웹 사이트의 모드 기능을 사용하여 웹소켓 추진을 사용한다는 것을 발견합니다.

멀티 스레드 병행

자바스크립트는 Go 함수를 통해 동시에 구현할 수 있으며, 파이썬은 그에 따른 멀티 스레드 라이브러리를 사용할 수 있다.

정량화 전략을 구현할 때, 많은 경우에, 동시 실행은 지연 승리의 효율성을 감소시킬 수 있다. 헤지징 전략 실판의 예를 들어, 두 개의 동전의 깊이를 얻어야 하며, 순서 실행 코드는 다음과 같다:

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

한 번 rest API를 요청할 때 지연이 있다고 가정하면 100ms입니다. 두 번의 깊이 획득 시간은 실제로 다릅니다. 더 많은 방문이 필요하면 지연 문제가 더 두드러지고 정책 실행에 영향을 미칩니다.

자바스크립트에는 많은 스레드가 없기 때문에 하부에는 Go 함수가 포괄되어 있습니다. Go 함수는 네트워크 접근이 필요한 API에 사용할 수 있습니다.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() //调用wait方法等待返回异步获取depth结果 
var depthB = b.wait()

대부분의 간단한 경우에, 이렇게 정책을 쓰는 것은 문제가 없습니다. 하지만 정책 루프마다 이 과정을 반복해야 한다는 점에 유의하십시오. 중간 변수 a, b는 실제로 임시 보조일 뿐입니다. 만약 우리가 동시 작업이 매우 많다면, a와 depthA, b와 depthB 사이의 대조 관계를 추가로 기록해야 합니다. 우리의 동시 작업이 불확실할 때 상황은 더욱 복잡합니다. 따라서 우리는 함수를 구현하고자 합니다.

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}] //加入我们需要获取两个交易所的深度和账户,跟多的信息也可以放入,如订单Id,状态等。
var tasks = [ ] //全局的任务列表

function produce(){ //下发各种并发任务
  //这里省略了任务产生的逻辑,仅为演示
  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 //这里的v就是并发Go函数wait()的返回值,可以仔细体会下
                }))
    }
    _.each(jobs, function(t){
            t.run() //在这里并发执行所有任务
        })
    tasks = []
}
function main() {
    while(true){
        produce()         // 发出交易指令
        worker()        // 并发执行
        Sleep(1000)
    }
}

마치 한 번 둥지를 돌리는 것 같지만 간단한 기능을 구현하는 것은 실제로 코드 복잡성을 크게 단순화합니다. 우리는 단지 프로그램이 어떤 작업을 생성해야하는지 걱정해야하며 작업자가 자동으로 동시에 실행하고 그에 따른 결과를 반환합니다. 유연성이 많이 향상되었습니다.

Chart 함수 그림

초등 교과서 소개 도표는 추천 도표 자료집이며, 대부분의 경우 요구 사항을 충족시킬 수 있습니다. 추가 사용자 정의가 필요한 경우 직접 차트 객체를 조작할 수 있습니다.

Chart({…})내부 변수는 HighStock 및 HighCharts 객체이며, 추가로 하나의 변수를 추가했습니다.__isStock하이스토크가 아닌지 구분하기 위해. 하이스토크는 시간 순서에 더 초점을 맞춘 그래프이기 때문에 더 자주 사용된다. FMZ는 하이차트와 하이스토크의 기본 모듈을 기본 지원하지만 추가 모듈을 지원하지 않는다.

이 글은 다른 글과 비교해 볼 수 있습니다.https://www.highcharts.com/demo하이스톡의 예:https://www.highcharts.com/stock/demo▲ 이 예제들을 참조하여 FMZ에 쉽게 이식할 수 있는 코드를 참조하십시오.

추가 (add (([series indeks ((예: 0), 데이터]) 를 호출하여 지정된 인덱스의 시리즈에 데이터를 추가할 수 있으며, reset (reset)) 를 호출하여 빈 차트 데이터를 호출할 수 있으며, reset는 숫자의 매개 변수를 가지고 예약된 항목을 지정할 수 있습니다. 여러 차트를 표시하는 것을 지원하며, 구성 시 수직 매개 변수를 입력하면 됩니다. 예를 들어, 차트 1에는 두 개의 세리가 있고, 차트에는 세 개의 세리가 있으며, 추가를 지정할 때 0 1 순서 ID를 지정하면 차트 1의 두 개의 세리를 나타냅니다. 추가할 때 2 순서 ID를 지정하면 차트 2의 첫 번째 데이터를 나타냅니다. 3 순서 ID를 지정하면 차트의 첫 번째 세리의 데이터를 나타냅니다.

예를 들어:

var chart = { // 这个 chart 在JS 语言中 是对象, 在使用Chart 函数之前我们需要声明一个配置图表的对象变量chart。
    __isStock: true,                                    // 标记是否为一般图表,有兴趣的可以改成 false 运行看看。
    tooltip: {xDateFormat: '%Y-%m-%d %H:%M:%S, %A'},    // 缩放工具
    title : { text : '差价分析图'},                       // 标题
    rangeSelector: {                                    // 选择范围
        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'},                         // 坐标轴横轴 即:x轴, 当前设置的类型是 :时间
    yAxis : {                                           // 坐标轴纵轴 即:y轴, 默认数值随数据大小调整。
        title: {text: '差价'},                           // 标题
        opposite: false,                                // 是否启用右边纵轴
    },
    series : [                                          // 数据系列,该属性保存的是 各个 数据系列(线, K线图, 标签等..)
        {name : "line1", id : "线1,buy1Price", data : []},  // 索引为0, data 数组内存放的是该索引系列的 数据
        {name : "line2", id : "线2,lastPrice", dashStyle : 'shortdash', data : []}, // 索引为1,设置了dashStyle : 'shortdash' 即:设置 虚线。
    ]
};
function main(){
    var ObjChart = Chart(chart);  // 调用 Chart 函数,初始化 图表。
    ObjChart.reset();             // 清空
    while(true){
        var nowTime = new Date().getTime();   // 获取本次轮询的 时间戳,  即一个 毫秒 的时间戳。用来确定写入到图表的X轴的位置。
        var ticker = _C(exchange.GetTicker);  // 获取行情数据
        var buy1Price = ticker.Buy;           // 从行情数据的返回值取得 买一价
        var lastPrice = ticker.Last + 1;      // 取得最后成交价,为了2条线不重合在一起 ,我们加1
        ObjChart.add([0, [nowTime, buy1Price]]); // 用时间戳作为X值, 买一价 作为Y值 传入 索引0 的数据序列。
        ObjChart.add([1, [nowTime, lastPrice]]); // 同上。
        Sleep(2000);
    }
}

예를 들어, 이 그림은 이 그림의 표면을 사용했습니다.https://www.fmz.com/strategy/136056

재검토 단계

Python 로컬 리코딩

이 글은 이쪽에서 작성되었습니다.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__

# ------------------------------ 策略部分开始 --------------------------

print exchange.GetAccount()     # 调用一些接口,打印其返回值。
print exchange.GetTicker()

def adjustFloat(v):             # 策略中自定义的函数
    v = math.floor(v * 1000)
    return v / 1000

def onTick():
    Log("onTick")
    # 具体的策略代码


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

# ------------------------------ 策略部分结束 --------------------------

try:
    main()                     # 回测结束时会 raise EOFError() 抛出异常,来停止回测的循环。所以要对这个异常处理,在检测到抛出的异常后调用 task.Join() 打印回测结果。
except:
    print task.Join()         

사용자 정의 검색 데이터

exchange.SetData ((arr), 재검토 데이터 소스를 전환하여 사용자 정의 K선 데이터를 사용한다. 대수 arr, K선 기둥 데이터의 요소 배열 (즉: K선 데이터 배열, 일시적으로 JavaScript 재검토만을 지원한다).

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

[
    1530460800,    // time     时间戳
    2841.5795,     // open     开盘价
    2845.6801,     // high     最高价
    2756.815,      // low      最低价
    2775.557,      // close    收盘价
    137035034      // volume   成交量
]

데이터 소스는 템플릿 큐브에 가져오면 됩니다.

function init() {                                                          // 模板中的 init 初始化函数会在加载模板时,首先执行,确保 exchange.SetData(arr) 函数先执行,初始化,设置数据给回测系统。
    var arr = [                                                            // 回测的时候需要使用的K线数据
        [1530460800,2841.5795,2845.6801,2756.815,2775.557,137035034],      // 时间最早的一根 K线柱 数据
        ... ,                                                              // K线数据太长,用 ... 表示,数据此处省略。
        [1542556800,2681.8988,2703.5116,2674.1781,2703.5116,231662827]     // 时间最近的一根 K线柱 数据
    ]
    exchange.SetData(arr)                                                  // 导入上述 自定义的数据
    Log("导入数据成功")
}

참고: 초기화 시 사용자 정의 데이터를 먼저 입력해야 합니다 (즉, 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为为支持交易所API基地址,注意不用添加/api/v3之类的,会自动补全

모든 거래소가 FMZ를 지원하지는 않지만, 이 플랫폼은 일반적인 프로토콜에 대한 접근 방법을 제공합니다.

  • 코드를 직접 작성하여 거래소에 접속하면 프로그램이 웹 서비스를 만듭니다.
  • FMZ 플랫폼에 거래소를 추가하고 네트워크 서비스의 주소와 포트를 지정합니다.
  • 관리자가 일반 프로토콜을 운영하는 거래소의 실제 디스크에서 정책의 API 액세스가 일반 프로토콜에 전송됩니다.
  • 일반 프로토콜은 요청에 따라 거래소를 방문하고 결과를 관리자에게 반환합니다.

간단히 말해서, 일반 프로토콜은 관리자의 요청을 대리하고 그에 따른 기준에 따라 데이터를 반환하는 중개인과 같습니다. 일반 프로토콜의 코드는 자체를 완료해야하며, 일반 프로토콜을 작성하는 것은 실제로 거래소에 개별적으로 액세스하여 정책을 완료 할 수 있음을 나타냅니다. FMZ 공식은 때때로 거래소의 일반 프로토콜 exe 버전을 발표합니다. 일반 프로토콜은 또한 파이썬을 사용하여 완료 할 수 있으며, 이 경우 일반 디스크로 운영 될 수 있습니다.

구체적인 협약의 소개:https://www.fmz.com/bbs-topic/1052파이썬의 일반적인 프로토콜의 예:https://www.fmz.com/strategy/101399

자사의 정량화 플랫폼을 만드는 것

거래소와 같은 모든 동작은 API를 통해 구현될 수 있으며, FMZ 웹사이트는 또한 API를 기반으로 합니다. 당신은 자신의 FMZ 웹사이트 API-KEY 구현을 신청할 수 있습니다.

FMZ 플랫폼의 강력한 확장성으로 인해 확장 API를 기반으로 자신의 양적 플랫폼을 만들 수 있으며 사용자가 당신의 플랫폼에서 실제 디스크를 실행하도록 할 수 있습니다. http://www.fmz.com/bbs-topic/1697

FMZ의 파트너가 되세요

온라인 클라우드 수업을 홍보합니다

디지털 화폐 거래 시장은 그것의 특수성 때문에 양적 거래자의 관심으로 점점 더 증가하고 있습니다. 실제로 프로그래밍 거래는 이미 디지털 화폐의 주류이며, 헤지업 시장과 같은 전략은 항상 시장에서 활발하지 않습니다.www.fmz.com이 코스는 처음 시작하는 사람들을 위한 20달러짜리 코스로, 4년 이상 수천 명의 초보자들이 양적 거래의 길을 걷도록 도와왔다.

홍보네티즌 클라우드 수업 디지털 화폐 양적 거래 과정◎ 登录网易云课堂,分享你的课程链接 (链接带独家courseId), 다른 사람들이 이 링크를 통해 등록하고 프로그램을 구입하면 50%의 총 10원 분배를 받게 된다.

복귀 캠페인을 홍보

소비자는 홍보 링크를 클릭하고, 6개월 이내에 등록을 통해 충전하면 유효한 주문에 유효한 금액에 따라 수수료를 반환합니다. 수수료는 승점 형태로 홍보자의 계좌로 반환됩니다. 사용자는 발명자의 양적 거래 플랫폼 계좌 잔액을 10:1 비율로 교환할 수 있습니다. 또한 나중에 발명자의 양적 주변 상품을 교환 할 수 있습니다.https://www.fmz.com/bbs-topic/3828

FMZ 정량화 플랫폼 기업판

전체 FMZ 웹사이트를 기업 또는 팀의 전용 서버에 배포하여 완전한 제어 및 기능 사용자 정의를 구현할 수 있다. FMZ 웹사이트는 약 10만 명의 사용자와 테스트를 거쳐 높은 사용성과 보안을 달성하여 양적 팀과 기업의 시간 비용을 절감할 수 있다. 엔터프라이즈 버전은 중견 양적 거래 팀, 상품 선물 서비스 업체 등을 대상으로 한 경우, 특정 제안 관리자 연락처이다.

도시 시스템

거래소에 시장 유동성 및 자금 관리를 제공하는 전문 시스템은 아마도 시장에서 가장 완벽한 시장을 만드는 시스템이며 많은 거래소 및 팀에서 사용됩니다.

거래소 프로그램

발명자 과학 거래 시스템은 메모리 촬영 기술을 적용하고, 주문 처리 속도가 최대 2 백만 페인트 / 초에 이르며, 주문 처리에는 지연 및 카튼이 발생하지 않도록 보장합니다. 동시에 온라인 사용자 수가 2 백만 명 이상인 거래소를 원활하게 안정적으로 운영 할 수 있습니다. 다층, 다중 클러스터 시스템 구조는 시스템의 보안, 안정성, 확장성을 보장합니다. 기능 배포, 버전 업데이트는 중단 없이 수행되며, 최종 사용자 운영 경험을 최대한 보장합니다. 현재 wex.app 모형 거래에서 시스템을 경험할 수 있습니다.


더 많은

2009년이 그룹에 가입할 수 있나요?

마이케오풀의 신, 무술!!

초목`` // 토큰 선물 추진 예제 var ACCESSKEYID = '당신의 토큰 계정의 액세스 키' var apiClient = Dial (('wss://api.hbdm.com/notification에 의해 압축=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 시간표 = utc_date.toISOSstring (().substring ((0,19) var quest = 'GET\napi.hbdm.com\n/notification\n'+'AccessKeyId='+ACCESSKEYID+'&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=' + encodeURIComponent (시간표) var signature = exchange.HMAC (("sha256", "base64", quest, "{{secretkey}}") ``

비트 군단만약 웹소켓이 가입 시장을 연결하는 경우, 시장을 위한 데이터를 read (()) 함수와 함께 얻을 수 있습니다. 만약 exchange.GetTicker (()) 를 사용한다면, 로컬 캐시에서 데이터를 추출하는 것이 아니라, rest 요청을 실행하여 데이터를 반환합니다. 토큰 단 하나만 지원하는 것은 exchange.IO (websocket) 를 통해 시장의 수용 방식을 변경하고, 그 다음 exchange.GetTicker (exchange.GetTicker) 및 exchange.GetDepth (exchange.GetDepth)) 를 사용하여 거래소 rest에 데이터를 요청하지 않고, 로컬 버퍼에 존재하는 이미 수신된 가입 시장에서 데이터를 얻을 수 있습니다. 저는 이해합니다, 그렇죠?

초목지시에 따라 확인하세요

슬리유다음으로 FMZ 텔레그램 그룹에서 확인된 정보는

티엘괜찮아

초목네, 모든 웹소켓이 다이얼을 사용하는 것이 좋습니다.