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

K-라인 데이터 처리가 절차적 거래에 대한 소소한 이야기

저자:발명가들의 수량화 - 작은 꿈, 2019-08-13 11:11:38, 업데이트: 2023-10-20 20:06:13

img

K-라인 데이터 처리가 절차적 거래에 대한 소소한 이야기

프로그래밍 트레이딩 전략을 작성할 때, K 라인 데이터를 사용하는 경우, 종종 12분 주기 K 라인 데이터나 4시간 주기 K 라인 데이터와 같은 비표준 주기 K 라인 데이터를 사용하는 것이 요구되는 경우가 있습니다. 일반적으로 이러한 비표준 주기는 직접적으로 얻을 수 없습니다. 그렇다면 우리는 이러한 요구를 어떻게 처리합니까? 이 질문에 대한 답은 분명히 있습니다. 비표준주기가 더 작은 주기의 데이터를 통한 합성 획득을 가능케 하고, 여러 주기의 최고가격은 합성 후 최고가격으로 계산되고, 최저가격은 합성 후 최저가격으로 계산되며, 개시 가격은 변하지 않는다. 합성 K선 원료 데이터의 첫 개시 가격, 폐쇄 가격은 합성 K선 원료 데이터의 마지막 폐쇄 가격과 대응하며, 시간이 걸리는 개시 가격의 시간, 거래량은 합성 K선 원료 데이터의 거래량으로 계산되고 수산된다. 이 사진들은 다음과 같습니다:

  • 생각해보세요.

    우리는 블록체인 자산 시장인 BTC_USDT를 예를 들어 1시간이 4시간으로 바뀌었습니다.

    img

    img

    img

    img

    시간 높은 열어요 낮은 접수
    2019.8.12 00:00 11447.07 11382.57 11367.2 11406.92
    2019.8.12 01:00 11420 11405.65 11366.6 11373.83
    2019.8.12 02:00 11419.24 11374.68 11365.51 11398.19
    2019.8.12 03:00 11407.88 11398.59 11369.7 11384.71

    이 4개의 1시간 주기의 데이터는, 4시간 주기의 루트 데이터로 합쳐져, 첫 번째 00:00 시점의 개시 가격인: 11382.57입니다. 마감값은 마지막 마감값인 03:00 마감값입니다: 11384.71 가장 높은 가격으로 가장 높은 가격을 찾아보세요:11447.07 가장 낮은 가격으로 가장 낮은 가격을 찾으세요: 11365.51 4시간 사이클의 시작 시간은 00:00 이 1시간 K 라인의 시작 시간은 2019.8.12 00:00 거래량 1시간에 한 번의 수요와 합 (거래량 데이터에 표시되지 않은 주요 가격 합성 관찰) 은 여기서 설명되지 않습니다.

    4시간짜리 K줄은 다음과 같습니다. 높이는:11447.07 오픈: 11382.57 낮은: 11365.51 집합: 11384.71 시간: 2019년 8월 12일 00:00

    img

    이 자료들은 모두 일치합니다.

  • 코드 작성 구현

    초기 아이디어가 검증된 후, 직접 코드를 작성하여 이 필요를 초기적으로 달성할 수 있습니다.

    코드는 레퍼런스 학습용입니다:

      function GetNewCycleRecords (sourceRecords, targetCycle) {    // K线合成函数
          var ret = []
          
          // 首先获取源K线数据的周期
          if (!sourceRecords || sourceRecords.length < 2) {
              return null
          }
          var sourceLen = sourceRecords.length
          var sourceCycle = sourceRecords[sourceLen - 1].Time - sourceRecords[sourceLen - 2].Time
    
          if (targetCycle % sourceCycle != 0) {
              Log("targetCycle:", targetCycle)
              Log("sourceCycle:", sourceCycle)
              throw "targetCycle is not an integral multiple of sourceCycle."
          }
    
          if ((1000 * 60 * 60) % targetCycle != 0 && (1000 * 60 * 60 * 24) % targetCycle != 0) {
              Log("targetCycle:", targetCycle)
              Log("sourceCycle:", sourceCycle)
              Log((1000 * 60 * 60) % targetCycle, (1000 * 60 * 60 * 24) % targetCycle)
              throw "targetCycle cannot complete the cycle."
          }
    
          var multiple = targetCycle / sourceCycle
    
    
          var isBegin = false 
          var count = 0
          var high = 0 
          var low = 0 
          var open = 0
          var close = 0 
          var time = 0
          var vol = 0
          for (var i = 0 ; i < sourceLen ; i++) {
              // 获取 时区偏移数值
              var d = new Date()
              var n = d.getTimezoneOffset()
    
              if (((1000 * 60 * 60 * 24) - sourceRecords[i].Time % (1000 * 60 * 60 * 24) + (n * 1000 * 60)) % targetCycle == 0) {
                  isBegin = true
              }
    
              if (isBegin) {
                  if (count == 0) {
                      high = sourceRecords[i].High
                      low = sourceRecords[i].Low
                      open = sourceRecords[i].Open
                      close = sourceRecords[i].Close
                      time = sourceRecords[i].Time
                      vol = sourceRecords[i].Volume
    
                      count++
                  } else if (count < multiple) {
                      high = Math.max(high, sourceRecords[i].High)
                      low = Math.min(low, sourceRecords[i].Low)
                      close = sourceRecords[i].Close
                      vol += sourceRecords[i].Volume
    
                      count++
                  }
    
                  if (count == multiple || i == sourceLen - 1) {
                      ret.push({
                          High : high,
                          Low : low,
                          Open : open,
                          Close : close,
                          Time : time,
                          Volume : vol,
                      })
                      count = 0
                  }
              }
          }
    
          return ret 
      }
    
      // 测试
      function main () {
          while (true) {
              var r = exchange.GetRecords()                           // 原始数据,作为合成K线的基础K线数据,例如要合成4小时K线,可以用1小时K线作为原始数据。
              var r2 = GetNewCycleRecords(r, 1000 * 60 * 60 * 4)      // 通过 GetNewCycleRecords 函数 传入 原始K线数据 r , 和目标周期, 1000 * 60 * 60 * 4 即 目标合成的周期 是4小时K线数据。
    
              $.PlotRecords(r2, "r2")                                 // 策略类库栏 可以勾选画线类库,调用 $.PlotRecords 画线类库 导出函数 画图。
              Sleep(1000)                                             // 每次循环间隔 1000 毫秒,防止访问K线接口获取数据过于频繁,导致交易所限制。
          }
      }
    

    사실 K줄을 합성하려면 두 가지가 필요합니다. 첫 번째는 원료 데이터, 즉 작은 주기의 K줄 데이터입니다.var r = exchange.GetRecords()소주기 K선 데이터를 얻을 수 있다. 둘째, 얼마나 큰 주기가 되는지 명확하게 합쳐야 한다. 즉, K선 데이터를 합성하는 목표 주기가 된다. 그 다음 GetNewCycleRecords 함수의 알고리즘을 통해, 최종적으로 합성된 K선 배열 구조의 데이터를 반환할 수 있다. 이 글의 내용은 다음과 같습니다.

    • 1, 목표 주기는 GetNewCycleRecords 함수를 데이터 원료로 입력하는 K줄의 주기에 비해 작을 수 없습니다. 작은 주기로 더 작은 주기로 데이터를 합성할 수 없기 때문입니다.

    • 2, 설정된 목표 주기는 주기가 닫혀 있어야 한다. 어떤 것이 '순환 폐쇄'인가? 간단히 말해서, 한 시간 또는 하루 동안의 목표 주기의 시간 범위가 결합되어 닫힌 루프를 형성합니다. 예를 들어: 예를 들어, 12분 주기의 K 라인은 0분 0초부터 시작하며 (예를 들어 0시) 첫 번째 주기는00:00:00 ~ 00:12:00두 번째 주기는00:12:00 ~ 00:24:00그리고 세 번째 주기는00:24:00 ~ 00:36:004번째 주기는00:36:00 ~ 00:48:005번째 주기는00:48:00 ~ 01:00:00이 글은 한 시간 동안 진행될 수 있는 글입니다.

      13분 주기가 닫히지 않은 주기가 될 경우, 이러한 주기가 계산되는 데이터는 독특하지 않습니다. 왜냐하면 합성된 데이터의 시작점이 다르기 때문에 합성 된 데이터는 다릅니다.

    이 비디오는 한 번에 실행됩니다.img

    거래소 차트img

  • K선 데이터로 구성될 수 있는 데이터 구조

    제 친구들은 종종 묻습니다. "나는 K줄마다 가장 높은 평균값을 계산하고 싶어요. 어떻게 할까요?"

    보통 우리가 계산하는 평균선은 계산된 종료 가격의 평균값이며, 평균선을 구성하지만, 때로는 최고 가격, 최저 가격, 개시 가격 등을 계산할 필요가 있습니다. 그리고 이 모든 것은exchange.GetRecords()함수가 반환하는 K선 데이터는 지표 계산 함수에 직접 전달됩니다.

    예를 들어:talib.MA평선 지표 계산 함수는 두 개의 매개 변수를 가지고 있으며, 첫 번째 매개 변수는 입력해야 할 데이터이며 두 번째 매개 변수는 지표 주기 매개 변수이다. 예를 들어, 이 그림의 지수를 계산해보죠img

    K선 주기는 4시간이고, 거래소 차트에서 평균 라인이 설정되어 있으며 평균 라인의 주기 매개 변수는 9이다. 그리고 계산된 데이터 소스는 각 바에 대한 최고 가격으로 설정됩니다.img즉, 이 평균선은 9개의 4시간 주기의 K 라인 바의 최고 가격 평균을 계산한 평균값이며, 구성된 지표의 평균선이다.

    우리는 직접 데이터 계산을 만들어서 거래소의 그래프와 같은 계산이 가능한지 확인했습니다.

    var highs = []
    for (var i = 0 ; i < r2.length ; i++) {
        highs.push(r2[i].High)
    }
    

    각 바르의 가장 높은 가격을 계산하기 위해 평균값을 계산하면 평선 지표가 나오죠. 그러면 먼저 각 데이터 요소가 각 바의 최대값에 해당하는 배열을 구성해야 합니다. highs 변수가 빈 행렬로 시작되는 것을 볼 수 있습니다. 그리고 우리는 r2이라는 K선 데이터 변수를 거슬러 올라갑니다. r2의 각 바에 대한 최고값을 읽는다 (즉, r2[i].High, i는 0에서 r2.length-1까지의 범위에서 값을 취한다) 그리고 highs로 푸시한다. 이렇게 K선 데이터 Bar에 하나씩 대응하는 데이터 구조를 구성한다.

    이 때 highs는 talib.MA 함수에서 계산된 평선으로 전달될 수 있다.

    : :

    function main () {
        while (true) {
            var r = exchange.GetRecords()
            var r2 = GetNewCycleRecords(r, 1000 * 60 * 60 * 4)
            if (!r2) {
                continue
            }
            
            $.PlotRecords(r2, "r2")                                               // 画出K线
            
            var highs = []
            for (var i = 0 ; i < r2.length ; i++) {
                highs.push(r2[i].High)
            }
            
            var ma = talib.MA(highs, 9)                                           // 用均线指标函数 talib.MA 计算 均线指标
            $.PlotLine("high_MA9", ma[ma.length - 2], r2[r2.length - 2].Time)     // 使用画线类库把均线指标画在图表上
            
            Sleep(1000)
        }
    }
    

    다시 테스트 실행:

    img

    이 그래프에서 마우스의 정지 위치의 평균 지표값은11466.9289

    위의 코드는 정책에서 테스트를 실행하는 데 복사할 수 있습니다. "그림줄 클래스 라이브러리"를 선택하고 저장하는 것을 기억하세요!

  • 디지털 통화 시장의 K 라인 데이터 취득 방법

    발명가들의 양적 거래 플랫폼은 이미 K선 데이터를 얻을 수 있는 Exchange.GetRecords 함수라는 포장된 인터페이스를 가지고 있다. 아래의 설명은 직접 거래소 K 라인 데이터 인터페이스를 액세스하여 데이터를 획득하는 데 중점을두고 있습니다. 때로는 더 많은 K 라인을 획득하기 위해 파라미터를 지정해야하기 때문에 포장된 GetRecords 인터페이스 일반적으로 100개의 K줄을 반환한다. 정책이 초기적으로 100개 이상의 K줄을 필요로 하는 경우 대기 수집이 필요하다. 정책을 최대한 빨리 실행하기 위해, 함수를 자체적으로 포괄하여, 거래소 K 라인 인터페이스에 직접 접속하여, 더 많은 K 라인 데이터를 얻기 위해 매개 변수를 지정할 수 있습니다.

    우리는 BTC_USDT 거래 쌍을 통해 이 요구를 달성했습니다.

    K 라인 인터페이스 설명서를 참조하여 거래소의 API 문서를 찾을 수 있습니다.img

    https://api.huobi.pro/market/history/kline?period=1day&size=200&symbol=btcusdt
    

    파라미터:

    변수 이름 유형 필요한가요? 설명 값 추출
    기호 문자열 사실 거래 , ,
    기간 문자열 사실 데이터의 시간적 입자를 반환합니다. 1분, 5분, 15분, 30분, 60분, 1일, 1개월, 1주, 1년
    크기 정수 거짓 K선 데이터 레코드를 반환합니다. [1, 2000]

    테스트 코드:

    function GetRecords_Huobi (period, size, symbol) {
        var url = "https://api.huobi.pro/market/history/kline?" + "period=" + period + "&size=" + size + "&symbol=" + symbol
        var ret = HttpQuery(url)
        
        try {
            var jsonData = JSON.parse(ret)
            var records = []
            for (var i = jsonData.data.length - 1; i >= 0 ; i--) {
                records.push({
                    Time : jsonData.data[i].id * 1000,
                    High : jsonData.data[i].high,
                    Open : jsonData.data[i].open,
                    Low : jsonData.data[i].low,
                    Close : jsonData.data[i].close,
                    Volume : jsonData.data[i].vol,
                })
            }
            return records
        } catch (e) {
            Log(e)
        }
    }  
    
    
    function main() {
        var records = GetRecords_Huobi("1day", "300", "btcusdt")
        Log(records.length)
        $.PlotRecords(records, "K")
    }
    

    토큰 거래소 인터페이스에 접근하는 파이썬 버전의 예시:

#!python3
import json
import urllib2

def GetRecords_Huobi(period, size, symbol):
    headers = {'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
    url = "https://api.huobi.pro/market/history/kline?" + "period=" + period + "&size=" + size + "&symbol=" + symbol
    request = urllib2.Request(url)  
    request.add_header('User-Agent','Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6')  
    opener = urllib2.build_opener()  
    f= opener.open(request)  
    ret = f.read().decode('utf-8')  
    
    try :
        jsonData = json.loads(ret)
        
        records = []
        for i in range(len(jsonData["data"]) - 1, -1, -1):
            records.append({
                "Time" : jsonData["data"][i]["id"] * 1000, 
                "High" : jsonData["data"][i]["high"], 
                "Open" : jsonData["data"][i]["open"], 
                "Low" : jsonData["data"][i]["low"], 
                "Close" : jsonData["data"][i]["close"], 
                "Volume" : jsonData["data"][i]["vol"], 
            })
        return records
    except Exception as e:
        Log(e)
        
def main():
    r = GetRecords_Huobi("1day", "300", "btcusdt")
    Log(len(r))
    ext.PlotRecords(r, "K")   # 需要引用Python画线类库


파이썬 버전, 비트코인 거래소에 접근하는 K 라인 인터페이스의 예:

#!python3
import json
import urllib2

def GetRecords_Huobi(period, size, symbol):
    headers = {'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
    url = "https://api.binance.com/api/v3/klines?symbol=" + symbol + "&interval=" + period
    request = urllib2.Request(url)  
    request.add_header('User-Agent','Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6')  
    opener = urllib2.build_opener()  
    f= opener.open(request)  
    ret = f.read().decode('utf-8')  
    try :
        jsonData = json.loads(ret)
        
        records = []
        for i in range(len(jsonData)):
            records.append({
                "Time" : float(jsonData[i][0]),
                "High" : float(jsonData[i][2]), 
                "Open" : float(jsonData[i][1]), 
                "Low" : float(jsonData[i][3]), 
                "Close" : float(jsonData[i][4]), 
                "Volume" : float(jsonData[i][5]), 
            })
        return records
    except Exception as e:
        Log(e)
        
def main():
    r = GetRecords_Huobi("1m", "300", "BTCUSDT")
    Log(len(r))
    ext.PlotRecords(r, "K")   # 需要引用Python画线类库


img

img

로그에서 볼 수 있듯이, records.length를 300으로 인쇄합니다.img


관련

더 많은

이 문제를 고칠 수 있을까요? 3시간이나 6시간의 K일 합성이 불가능합니다.

if (((1000 * 60 * 60 * 24) - sourceRecords[i].Time % (1000 * 60 * 60 * 24) + (n * 1000 * 60)) % targetCycle == 0) { isBegin = true ♪ ♪ 이 문장에는 문제점이 있습니다. 3시간이나 6시간의 k일과 1시간, 2시간, 4시간의 k일만 합성할 수 있습니다.

xis2004만약 여러분이 한 종의 모든 역사적 자료를 올라갈 수 있다면?

윌장감사합니다.

윌장300개 이상의 데이터를 원하는 경우 어떻게 처리하는 것이 더 좋을까요? 예를 들어 1000개의 K 라인 데이터. 거래소는 한번에 300개씩 지원하는 것 같습니다. 감사합니다.

발명가들의 수량화 - 작은 꿈좋은, 시간이 좀 더 걸릴 겁니다.

발명가들의 수량화 - 작은 꿈이것은 거래소 인터페이스 데이터에 액세스하는 것입니다. 거래소가 당신에게 얼마나 많은 데이터를 주는지입니다. 즉, 일반적으로 몇 백 개의 최신 바입니다.

발명가들의 수량화 - 작은 꿈만약 거래소 인터페이스가 지원하는 최대 반환 수를 초과한다면, 이것은 단지 데이터를 수집할 수 있고, 충분한 K 라인 데이터만 수집할 수 있다.