자바스크립트와 함께 게임을 하는 노인 (老白) - 구매를 하는 파트너를 만드는 (6) 로봇이 사용하는 도구 코드를 개발

저자:작은 꿈, 2017-03-15 11:22:52, 업데이트: 2017-10-11 10:37:43

노인과 함께 자바스크립트 을 플레이하여 구매하는 파트너를 만듭니다.


로봇 개발 과정에서 많은 작은 코드 조각이 축적되어 있으며, 일부는 자신의 정량화 전략 프로그램에서 활용 할 수 있습니다.

  • 1, 임의의 K선 주기를 변환합니다

    이 코드 모듈은 클래스 라이브러리로 작성되지 않고 함수를 작성하는 것뿐이며, 후속 변경을 용이하게 확장할 수 있다. 역할은 특정 주기의 기본 K 라인 데이터에 따라 대주기를 합성하는 K 라인이다. 평상시 시장을 보거나 플랫폼 작성을 사용하는 경우 기본 설정은 일반적으로 사용되는 주기의 K 라인, 예를 들어 1 일, 1 시간, 1 분, 기타입니다. 다른 주기의 데이터를 처리해야하는 경우, 예를 들어 4 시간, 6 시간, 8 시간 K 라인, 그러면 직접 시작해야합니다. 그래서 이것을 작성했습니다. 이 글의 원본 주소는:https://www.fmz.com/strategy/35986

    // K线周期合成  扩展为 根据基础K线 合成 为任意周期。
    

var cloneObj = function ((obj) { // 깊이 복사 객체 함수 var str, newobj = obj.constructor === Array? [] : {}; if (typeof obj!== object) { JSON (JSON) { str = JSON.stringify ((obj); // 시리즈화 대상 newobj = JSON.parse ((str); // 복원 } else { for (var i in obj) { newobj[i] = typeof obj[i] === object? cloneObj ((obj[i]) : obj[i]; ♪ ♪ ♪ ♪ return newobj; }; 이 모든 것은 var DAY = 0; var HOURS = 1; var MINUTES = 2; var isFirstFind = true; var FirstStamp = null; 이 모든 것은 function GetDHM ((objTime, BaseCycle, NewCycleForMS) { var ret = []; if ((BaseCycle % (1000 * 60 * 60 * 24) === 0) { ret[0] = objTime.getDate ((); ret[1] = DAY; }else if ((BaseCycle % (1000 * 60 * 60) === 0) { ret[0] = objTime.getHours ((); ret[1] = HOURS; }else if ((BaseCycle % (1000 * 60) === 0) { ret[0] = objTime.getMinutes ((); ret[1] = MINUTES; ♪ ♪ if ((NewCycleForMS % (1000 * 60 * 60 * 24) === 0) { ret[2] = DAY; }else if ((NewCycleForMS % (1000 * 60 * 60) === 0) { ret[2] = HOURS; }else if ((NewCycleForMS % (1000 * 60) === 0) { ret[2] = MINUTES; ♪ ♪ ret; ♪ ♪ 이 모든 것은 search functionFirstTime ((ret, BaseCycle, NewCycleForMS) {) if(ret[1] === DAY && ret[2] === DAY) { var array_day = []; for ((var i = 1 ; i < 29; i += (NewCycleForMS / BaseCycle)) { array_day.push ((i); ♪ ♪ for ((var j = 0 ; j < array_day.length; j++ ) { if(ret[0] === array_day[j]) { return true: 사실로 반환 ♪ ♪ ♪ ♪ }else if(ret[1] === HOURS && ret[2] === HOURS) { var array_hours = []; for ((var i = 0 ; i < 24; i += (NewCycleForMS / BaseCycle)) { array_hours.push ((i)); ♪ ♪ for ((var j = 0 ; j < array_hours.length ; j++) { if ((ret[0] === array_hours[j]) { return true: 사실로 반환 ♪ ♪ ♪ ♪ }else if(ret[1] === MINUTES && ret[2] === MINUTES) { var array_minutes = []; for ((var i = 0; i < 60; i += (NewCycleForMS / BaseCycle)) { array_minutes.push ((i); ♪ ♪ for ((var j = 0; j < array_minutes.length; j++) { if ((ret[0] === array_minutes[j]) { return true: 사실로 반환 ♪ ♪ ♪ ♪ 다른 사람 throw 목표 주기가 기본 주기와 일치하지 않습니다! 목표 주기의 밀리 초수: + NewCycleForMS + " 기본 주기의 밀리 초수: " + BaseCycle; ♪ ♪ ♪ ♪ 이 모든 것은 function Calc_High ((AssRecords, n, BaseCycle, NewCycleForMS) { var max = AssRecords[n].High; for ((var i = 1 ; i < NewCycleForMS / BaseCycle; i++) { max = Math.max ((AssRecords[n + i].High, max); ♪ ♪ 이 경우, ♪ ♪ 이 모든 것은 function Calc_Low ((AssRecords, n, BaseCycle, NewCycleForMS) { var min = AssRecords[n].Low; for ((var i = 1 ; i < NewCycleForMS / BaseCycle; i++) { min = Math.min ((AssRecords[n + i].Low, min); ♪ ♪ 이 문서는 ♪ ♪ 이 모든 것은 function AssembleRecords ((records, NewCycleForMS) {) var AssRecords = records.slice ((0); // 깊은 복사 var AfterAssRecords = [];

if(!records || records.length < 2){
    throw (!records) ? "传入的records参数为 错误" + records : "基础K线长度小于2";
}
var BaseCycle = records[records.length - 1].Time - records[records.length - 2].Time;
if(NewCycleForMS % BaseCycle !== 0){
    throw "目标周期‘" + NewCycleForMS + "’不是 基础周期 ‘" + BaseCycle + "’ 的整倍数,无法合成!";
}
if(NewCycleForMS / BaseCycle > records.length){
    throw "基础K线数量不足,请检查是否基础K线周期过小!";
}

// 시간 을 판단하고, 목표 K 라인의 시작 시간에 대한 기본 K 라인의 시작 시간을 찾습니다. var objTime = new Date ((); for (var i = 0; i < AssRecords.length; i++) { objTime.setTime ((AssRecords[i].Time)); var ret = GetDHM ((objTime, BaseCycle, NewCycleForMS));

    if (isFirstFind === true && SearchFirstTime(ret, BaseCycle, NewCycleForMS) === true) {
        FirstStamp = AssRecords[i].Time;
        for (j = 0; j < i; j++) {
            AssRecords.shift();        // 把目标K线周期前不满足合成的数据排除。
        }
        isFirstFind = false;
        break;                         // 排除后跳出
    }else if(isFirstFind === false){
        if((AssRecords[i].Time - FirstStamp) % NewCycleForMS === 0){
            for (j = 0; j < i; j++) {
                AssRecords.shift();    // 把目标K线周期前不满足合成的数据排除。
            }
            break;
        }
    }
}
var BarObj = {                         // 定义一个 K线柱结构
    Time: 0,
    Open: 0,
    High: 0,
    Low: 0,
    Close: 0,
    Volume: 0,
};
var n = 0;
for (n = 0; n < AssRecords.length - (NewCycleForMS / BaseCycle); n += (NewCycleForMS / BaseCycle)) {     // 合成
    /*
    {
    Time    :一个时间戳, 精确到毫秒,与Javascript的 new Date().getTime() 得到的结果格式一样
    Open    :开盘价
    High    :最高价
    Low :最低价
    Close   :收盘价
    Volume  :交易量
    }
    */
    BarObj.Time = AssRecords[n].Time;
    BarObj.Open = AssRecords[n].Open;
    BarObj.High = Calc_High(AssRecords, n, BaseCycle, NewCycleForMS); 
    BarObj.Low =  Calc_Low(AssRecords, n, BaseCycle, NewCycleForMS); 
    BarObj.Close = AssRecords[n + (NewCycleForMS / BaseCycle) - 1].Close;
    BarObj.Volume = AssRecords[n + (NewCycleForMS / BaseCycle) - 1].Volume;
    AfterAssRecords.push(cloneObj(BarObj));
}

BarObj.Time = AssRecords[n - (NewCycleForMS / BaseCycle) ].Time + NewCycleForMS; // 마지막 시간은 변경할 수 없습니다. BarObj.Open = AssRecords[n].Open; BarObj.Close = AssRecords [AssRecords.length - 1].Close; BarObj.Volume = AssRecords[AssRecords.length - 1].Volume; var max = AssRecords[n].High; var min = AssRecords[n].Low; for ((var index_n = n + 1 ;index_n < AssRecords.length; index_n++) { max = Math.max ((max, AssRecords[index_n].High); min = Math.min ((min, AssRecords[index_n].Low); ♪ ♪ BarObj.High = max; BarObj.Low = min; AfterAssRecords.push ((cloneObj ((BarObj)));

return AfterAssRecords;

♪ ♪ 이 모든 것은 function main() { // 테스트 코드 while(!exchange.IO(status) { LogStatus (연결되지 않은 로그!로그) ♪ ♪ var Info = _C ((exchange.SetContractType, MA705); // 테스트 메탈올 705 계약의 K선 데이터 합성 var records = exchange.GetRecords (); while (!records.length < 24) { records = exchange.GetRecords (); ♪ ♪
// 인터페이스 매개 변수를 처리합니다. var Num_UI_NewCycleForMS = 1; var arrayNum = UI_NewCycleForMS.split (("*"); for ((var indexNum = 0 ; indexNum < arrayNum.length ; indexNum++) { Num_UI_NewCycleForMS = Num_UI_NewCycleForMS * 숫자 (열음 숫자 [인덱스 숫자]); ♪ ♪ Log (( 사용자 지정 주기가 밀리 초 시간입니다: , Num_UI_NewCycleForMS);
while (true) { while (true) } records = _C (exchange.GetRecords); // Log ( 원 K줄 데이터: 길이 , records.length, 데이터: , records); records = AssembleRecords ((records, Num_UI_NewCycleForMS); // 첫 번째 매개 변수는 기본 K 라인, 두 번째 매개 변수는 변환하려는 주기의 밀리초 수, 1000 * 60 * 20 즉 20 분으로 변환 // Log (가 변환된 후 K줄 데이터: 길이 , records.length, 데이터: , records); $PlotRecords ((records, BTC ); // throw stop ; // ceshi Sleep ((1000); ♪ ♪ ♪ ♪


- #### 2、传统期货差价监控 (CTP)

当需要分析两个品种差价走势的时候,会用上这段代码。有时候也会把这段代码修改集成到自己的策略程序里面(比如跨期对冲策略),代码会绘制出一个差价走势图,在学习如何让机器人程序画图也是很有帮助的,很好的例子。
源码地址: https://www.fmz.com/strategy/5379

var __lastDiff = 0; var __AType = [Last, Buy, Sell][AType]; var __BType = [Last,Buy,Sell][BType]; 이 모든 것은 function _N ((v, precision) { if (typeof(precision)!= number ) { 정밀도 = 4; ♪ ♪ var d = parseFloat ((v.toFixed ((Math.max ((10, precision + 5))); s = d.toString (().split ((""); if (s.length < 2명의 s[1].length <= precision) { return d; ♪ ♪ 이 모든 것은 var b = Math.pow ((10, precision); return Math.floor ((d * b) / b; ♪ ♪ 이 모든 것은 함수 EnsureCall ((method) { var r; while (!(r = method.apply(this, Array.prototype.slice.call ((arguments).slice))) { 잠자리 (Interval); ♪ ♪ r를 반환합니다 ♪ ♪ 이 모든 것은 function on Tick ((() { var a = EnsureCall ((exchange.SetContractType, AInstrument); var tickerA = EnsureCall ((exchange.GetTicker)); var b = EnsureCall ((exchange.SetContractType, BInstrument)); var tickerB = EnsureCall (exchange.GetTicker) 이 있습니다. var diff = _N (tickerA[__AType] - tickerB[__BType]); LogStatus ((a.InstrumentName, _N ((tickerA[__AType]), b.InstrumentName, _N ((tickerB[__BType]), 차이: , diff); if (__lastDiff!=0) { if (Math.abs(Math.abs(diff) - Math.abs ((__lastDiff)) > 200) { ♪ ♪ ♪ ♪ if (diff!= __lastDiff) { // add는 세리에 데이터를 추가합니다. 파라미터 형식은 [series 계열 번호, 데이터]입니다. __chart.add (([0, [new Date (().getTime ((), diff))); __lastDiff = diff; ♪ ♪ ♪ ♪ 이 모든 것은 function main (() { if (exchange.GetName().indexOf(Futures_CTP) == -1) { 은 전통적인 선물 (CTP) 만을 지원합니다. ♪ ♪ SetErrorFilter (loginready에 의해 접속이 실패한 경우) // Chart 함수에게 전달되는 것은 문맥과 무관한 구조물이어야 합니다. __chart = Chart (차트) 도구 팁: { xDateFormat: %Y-%m-%d %H:%M:%S, %A title: { text: 가격 분석 도표 rangeSelector: { 버튼: [{ hour, hour 1번 니다 text: 1h {} hour, hour 카운트: 3 text: 3h {} hour, hour 8번 text: 8h {} all, text: All [그것에 대해 더 자세히 알아보기] selected: 0 입력Enabled: false x축: { type: 날짜시간 표시 y축: { 플롯 라인: [{ value: NormalDiff 색상: 그린 , dashStyle: shortdash , shortdash , shortdash , shortdash , shortdash , shortdash , shortdash , shortdash , shortdash width: 1, {} 밸류: HighDiff, 색: 붉은색 dashStyle: shortdash , shortdash , shortdash , shortdash , shortdash , shortdash , shortdash , shortdash , shortdash width: 1, {} -NormalDiff, -NormalDiff, -NormalDiff, -NormalDiff, -NormalDiff, -NormalDiff, 색상: 그린 , dashStyle: shortdash , shortdash , shortdash , shortdash , shortdash , shortdash , shortdash , shortdash , shortdash width: 1, {} -HighDiff, -HighDiff, -HighDiff, -HighDiff, 색: 붉은색 dashStyle: shortdash , shortdash , shortdash , shortdash , shortdash , shortdash , shortdash , shortdash , shortdash width: 1, ♪ [{] name: 오리온 가격이 떨어지고, 데이터: [], 도구 팁: { valueDecimals: 2 ♪ ♪ ♪ }); // reset 모든 그래프 전 정보를 비어 // __chart.reset ((); var a = EnsureCall ((exchange.SetContractType, AInstrument); var b = EnsureCall ((exchange.SetContractType, BInstrument)); 로그 (a.InstrumentName + . + __AType, -, b.InstrumentName + . + __BType, 의 차이는 수익으로 표시되는 그래프 ); TickInterval = Math.max (TickInterval, 50); Interval = Math.max (Interval, 50); while (true) { (onTick)) [Sleep (TickInterval) ]; [Sleep (TickInterval) ]; ♪ ♪ ♪ ♪


- #### 3、CTP手动全平CTP商品期货持仓

在Simnow 上测试 商品期货策略时经常需要把已经开过的仓位平掉重新测试代码,这样就需要个类似一键平仓的程序来处理 恢复模拟账号未开仓状态。这里使用了一个交易处理模块: $.NewPositionManager 就是该模块的接口函数,作用是生成一个对象,可以调用该对象的方法处理具体操作,比如 全平仓: CoverAll(); 。  做了一点额外的功能,在全部平仓完以后,会打印出所有交易的标的物名称。

var p = $.NewPositionManager ((); 함수 main() { while (진짜) 만약exchange.IO("status") === true) { p.CoverAll ((); var positions = _C ((exchange.GetPosition)); if ((positions.length === 0) { Log ((positions is :, positions); 브레이크; ♪ ♪ 다른 사람 LogStatus (서버에 연결되지 않은 상태, 대기 중) ♪ ♪ 2000년; ♪ ♪ var dict =exchange.IO("instruments"); // 거래소의 모든 상품 목록{ 제품 이름: 詳細} 사전 형식을 반환 for ((var k in dict) { Log (( 제품명:??, k, 자세한 정보: 제품명??, dict[k]); ♪ ♪ 로그 (exit., _C (exchange.GetPosition)); ♪ ♪

  
- #### 4、商品期货主力合约过滤

  在处理商品期货合约的连续性时会遇到主力合约的问题,如何更快的过滤识别出主力合约呢? 同样也写了个代码模块,可以改造,嵌入,或者单独使用。
  在 filter 变量中指定要 扫描的合约代码头。(即不含日期信息的合约代码的部分)  
    

var str = null; var strArray = []; function main (() { var filter = [MA,CF,zn,SR,pp,l,ni,i,v,jm,al,jd,cs,p]; var products = []; 로그 (거래 서버로 연결될 때까지 기다립니다) while (!exchange.IO(status) (Sleep ((1000)); 로그 (은 모든 계약을 획득하기 시작); var instruments = _C(exchange.IO그리고, instruments); 로그 ( 계약 목록에서 성공한을 얻는다); var len = 0; for (var instrumentId in instruments) { len++; ♪ ♪ 로그 ( 계약 목록의 길이는:??, len); for (var instrumentId in instruments) { if (instruments[instrumentId].IsTrading) { var found = false; for (var i = 0; i < filter.length; i++) { if (instruments[instrumentId].ProductID == filter[i]) { 이 문서는 검색어와 연결된 문서입니다 ♪ ♪ ♪ ♪ if (!found) { 계속하세요. ♪ ♪ if (typeof(products[instruments[instrumentId].ProductID]) === undefined ) { products[instruments[instrumentId].ProductID] = []; ♪ ♪ products[instruments[instrumentId].ProductID].push ((instrumentId) ]; ♪ ♪ ♪ ♪ for (var product in products) { (제품의 다양한 제품) var ss = products[product]; 로그 ( 구독, product,?? 의??, ss.length,?? 종 계약, 주력 계약을 식별하기 위해); var vol = 0, volIdx = 0; for (var i = 0; i < ss.length; i++) { _C ((exchange.SetContractType, ss[i]); ♪ ♪ [Sleep ((5000) ]] for (var i = 0; i < ss.length; i++) { _C ((exchange.SetContractType, ss[i]); var ticker = exchange.GetTicker (();

        if (ticker) {
            var obj = JSON.parse(exchange.GetRawJSON());
            if (obj.OpenInterest > vol) {
                vol = obj.OpenInterest;
                volIdx = i;
            }
        }
    }
    // 取消订阅行情(之后此合约K线将停止收集), 当然也可以不取消, 这里演示用
    for (var i = 0; i < ss.length; i++) {
        _C(exchange.SetContractType, "-" + ss[i]);
    }
    strArray.push(ss[volIdx]);
    Log("主力合约为", ss[volIdx], "持仓", vol, '#ff0000');
}
for(var i = 0 ; i < strArray.length; i++){
    str += strArray[i] + ',';
}
Log("主力合约:", str);

}


- #### 5、交互模块

  有时候需要给机器人交互,需要下命令、改参数、获取详细运行状态参数 就需要交互代码了。
  

function get_Command (() {// 상호작용을 담당하는 함수, 상호작용을 신속히 업데이트 var keyValue = 0;// 명령어에서 전달된 매개 변수 값 var way = null; // 라우터 var cmd = GetCommand ((); // 취득 상호 명령어 API if (cmd) { 로그 (,cmd 버튼을 누르면) / 로그 표시 arrStr = cmd.split ((":"); //GetCommand 함수가 반환하는 것은 문자열입니다. //, 그래서 먼저 문자열을 처리하고, 함수를 반환하는 문자열을:로 나누고 2개의 문자열로 저장합니다.

  if(arrStr.length === 2){//接受的不是 按钮型的,是数值型。
      jsonObjStr = '{' + '"' + arrStr[0] + '"' + ':' + arrStr[1] + '}'; // 把 字符串数组中的元素重新 
                                                                        //拼接 ,拼接成 JSON 字符串  用于转换为JSON 对象。
      jsonObj = JSON.parse(jsonObjStr); // 转换为JSON 对象

      for(var key in jsonObj){ // 遍历对象中的  成员名
          keyValue = jsonObj[key]; //取出成员名对应的 值 , 就是交互按钮的值
      }

      if(arrStr[0] == "upDateAmount"){// 此处为 数字型  。这里处理分为  按钮  和  数字型  。 详见 策略参数 设置界面 下的 交互设置
          way = 1;
      }
      if(arrStr[0] == "扩展1"){
          way = 2;
      }
      if(arrStr[0] == "扩展2"){
          way = 3;
      }
      if(arrStr[0] == "扩展3"){
          way = 4;
      }
  }else if(arrStr.length === 1){// 此处为 按钮型  
      //路由
      if(cmd == "cmdOpen"){ 
          way = 0;
      }
      if(cmd == "cmdCover"){
          way = 5;
      }
  }else{
      throw "error:" + cmd + "--" + arrStr;
  }
  switch(way){ // 分支选择 操作
      case 0://处理 发出开仓信号
          tiaojian = 1;
          break;
      case 1://处理
          Amount = keyValue;//把交互界面设置的 数值 传递给 Amount
          Log("开仓量修改为:",Amount);//提示信息
          break;
      case 2://处理

          break;
      case 3://处理

          break;
      case 4://处理

          break;
      case 5://处理 发出平仓信号
          tiaojian = 2;
          break;
      default: break;
  }

} }


  有时我们甚至需要在机器人运行时插入运行JS 代码:

var cmd = GetCommand ((); // API를 호출하여 인터페이스 인터랙션 컨트롤의 메시지를 얻는다. if (cmd) { // 메시지가 있는지 판단합니다 var js = cmd.split ((:, 2) [1]; //split 반환 메시지 문자열, 2를 반환하는 제한, 1의 인덱스 요소로 지정 js라는 변수에 값을 부여 Log (( 실행 디뷰팅 코드:??, js); // 출력 실행 코드 try { // 이상 탐지 eval ((js); //는 입력된 매개 변수 ((코드) 를 실행하는 eval 함수를 실행한다. } catch ((e) { // 오차를 던지다 Log ((Exception, e); // 오류를 출력합니다 ♪ ♪ ♪ ♪




当然还有很多代码工具尽在 : https://www.fmz.com/square


#### 先写到这,欢迎读者给我留言!提出建议和意见,如果感觉好玩可以分享给更多热爱程序热爱交易的朋友 
https://www.fmz.com/bbs-topic/735

### 程序员 littleDream 原创

더 많은