前几天看到一个CoreML的教程视频,感觉挺有意思的样子,所以去了解了一下,决议尝试将他用于猜测涨跌,看下机器学习的能不能猜测的准,就算不可,也无所谓,就相当于学习好了

demo传递门

模型类型

CoreML需求选定一个模型来进行练习

运用苹果的CoreML来生成一个机器学习的模型,用于测验虚拟币的5分k线的涨跌
翻开developer tool,然后点击New document就能够看到有多少类型
运用苹果的CoreML来生成一个机器学习的模型,用于测验虚拟币的5分k线的涨跌
前面几个都是图片分类,图片辨认,手势辨认文字辨认啥的,我也没细看,今天咱们就用表格的Tabular Regression来给他一些根底数据,让他来猜测

模型选型

曾经也想过给复杂的数据给他去练习,有点复杂,还是先给一些简单的了,我的想法就是以最后一根k线的涨跌幅作为方针,往前数五根k线作为根底数据

运用苹果的CoreML来生成一个机器学习的模型,用于测验虚拟币的5分k线的涨跌
生成模型需求准备一个csv文件,我准备像下面这样的格式,前面的k是根底数据,target是方针数据,这样的数据交给模型练习器进行练习

k0 k1 k2 k3 k4 target
0.09 -0.16 0.23 -0.06 0.07 -0.05
-0.16 0.23 -0.06 0.07 -0.05 -0.10
0.23 -0.06 0.07 -0.05 -0.10 0.05
-0.06 0.07 -0.05 -0.10 0.05 -0.06

单位是百分点

获取数据

要得到这样的数据,需求从买卖平台恳求过往的k线数据 我从币安的api接口查到接口和参数,然后查询从某个时刻开端的数据,一次恳求1500条,1500条乘以5分钟

open func requestCandles(startTime: Int? = nil, limit: Int? = nil) async throws -> (response: HTTPURLResponse, candles: [Candle]) {
    let path = "GET /api/v1/klines"
    var params = ["symbol": instId, "interval": intervalStr] as [String: Any]
    if let startTime = startTime {
      params["startTime"] = startTime
    }
    params["limit"] = limit ?? self.limit
    let response = await RestAPI.send(path: path, params: params)
    if response.succeed {
      if let data = response.data as? [[Any]] {
        var candles = [Candle]()
        for arr in data {
          let candle = Candle(array: arr)
          candles.append(candle)
        }
        return (response.res.urlResponse!, candles)
      } else {
        throw CommonError(message: "data类型不对")
      }
    } else {
      logInfo("恳求k线失利:(response.errMsg ?? "")")
      throw CommonError(message: response.errMsg ?? "")
    }
  }

通过接口测验,我发现最早只能查到2020/01/01 00:00:00的数据,时刻戳就是1577808000000, 所以我就起了一个定时器不断调用接口把数据拉下来

/// 执行一次恳求
  func request() async throws {
    let lastTime = lastTime ?? initStartTime
    let next = lastTime + 1
    do {
      logInfo("开端恳求(next.dateDesc)的数据")
      // 恳求当前时刻的k线
      let (response, candles) = try await candleManager.requestCandles(startTime: next)
      let requestCompletion = await self.saveCandles(candles)
      if !requestCompletion {
        // 恳求没完结,继续恳求下一页
        try await self.continueWith(response: response)
        return
      }
      logInfo("恳求完结,开端生成Candle模型")
      try await createCandleModels()
    } catch {
      logInfo("恳求失利:(error)")
    }
  }

Candle是一个根底的k线数据结构,CandleModel就是上面的模型了,一切Candle会拼装到一个数组中,然后再来生成一切的CandleModel,生成完之后,就开端拼装csv需求的格式了

生成csv文件

    /// 生成csv文件
  func createCSVFile() async throws {
    // 每行的内容
    var contents = [String]()
   
    // 文件表头
    let header = columns.joined(separator: ",")
    contents.append(header)
    logInfo("拼装Header:(header)")
   
    // 每天的
    for candleModel in candleModels {
      var lines = [String]()
      // 前面的涨跌幅
      lines += candleModel.previousCandles
        .map({ $0.rate })
     
      // 当天的涨跌幅
      if let current = candleModel.current {
        lines.append(current.rate)
      }
     
      // 当前的字符串
      let line = lines.joined(separator: ",")
      logInfo("拼装字符串:(line)")
      contents.append(line)
    }
    // 拼装成最后字符
    let content = contents.joined(separator: "n")
    if let data = content.data(using: .utf8) {
      try data.write(to: csvFileURL)
    }
   
    logInfo("生csv成功,准备生成CoreML模型")
    try await createML()
  }

运用苹果的CoreML来生成一个机器学习的模型,用于测验虚拟币的5分k线的涨跌
生成了一个14M的文件,模型还是比较多的

生成CoreML模型

接下来就是生成CoreML模型了

/// 生成模型
    func createML() async throws {
        guard FileManager.default.fileExists(atPath: csvFileURL.path()) else {
            print("csv路径不存在")
            throw CreateError.csvNotFound
        }
        // 生成MLTable
        let dataFrame = try DataFrame(contentsOfCSVFile: csvFileURL, columns: columns)
        // 划分数据,0.8用于练习,0.2用于验证
        let (trainingData, testingData) = dataFrame.randomSplit(by: 0.2, seed: 5)
        // 开端练习
        logInfo("开端练习")
        let regressor = try MLLinearRegressor(trainingData: DataFrame(trainingData), targetColumn: "rate")
        /// 获取练习成果
        let trainintError = regressor.trainingMetrics.error
        let trainintValid = regressor.trainingMetrics.isValid
        let worstTrainingError = regressor.trainingMetrics.maximumError
        logInfo("练习成果->: error: (String(describing: trainintError)),是否有用:(trainintValid),辨认率:(worstTrainingError)")
        let validationError = regressor.validationMetrics.error
        let validationValid = regressor.validationMetrics.isValid
        let worstValidationError = regressor.validationMetrics.maximumError
        logInfo("验证成果->: error: (String(describing: validationError)),是否有用:(validationValid),辨认率:(worstValidationError)")
        /// 评价
        logInfo("开端评价")
        let regressorEvalutation = regressor.evaluation(on: DataFrame(testingData))
        /// 评价e的成果
        let evalutationError = regressorEvalutation.error
        let evalutationValid = regressorEvalutation.isValid
        let worstEvaluationError = regressorEvalutation.maximumError
        logInfo("评价成果->: error: (String(describing: evalutationError)),是否有用:(evalutationValid),辨认率:(worstEvaluationError)")
        // 保存
        let regressorMetaData = MLModelMetadata(author: "zhtg@me.com", shortDescription: "BTC5mk线涨跌猜测模型", version: "1.0")
        try regressor.write(to: modelFileURL, metadata: regressorMetaData)
        // 测验
//        let testcsvFile = documentsPath + "/test.csv"
//        let testDataFrame = try DataFrame(contentsOfCSVFile: URL(filePath: testcsvFile), columns: ["first", "second"])
//        let pResult = try regressor.predictions(from: testDataFrame)
//        print("result: (pResult)")
        logInfo("完结生成")
//        xcrun coremlcompiler compile CandleModelRegressor.mlmodel .
//        xcrun coremlcompiler generate --language Swift CandleModelRegressor.mlmodel .
    }

有了csv也能够用developer tool来生成,我这里为了方便,就爽性用代码一同生成好了,其间有用和成果字段没用上,这个应该要判断一下,假如不满足,则直接中止的

生成的模型是一个CandleModelRegressor.mlmodel称号的,mlmodel结束,这个文件还不能够用于spm,用于xcode project却是能够,

不能够用于spm可能是bug,他编译的时分说缺少一个言语,可是spm没有设置言语的地方,走不下去了,只能别的想办法,google到能够手动编译,编译完再放进去就能够

xcrun coremlcompiler compile CandleModelRegressor.mlmodel .
xcrun coremlcompiler generate --language Swift CandleModelRegressor.mlmodel .

手动指令如上,他会生成以下两个文件,

运用苹果的CoreML来生成一个机器学习的模型,用于测验虚拟币的5分k线的涨跌

集成

拖入spm项目根目录即可, 然后target还要添加一个resource的配置,需求运用.copy,其他都不可

resources: [
  .copy("CandleModelRegressor.mlmodelc"),
   ]

运用

用的时分需求先生成一个regressor

    // 生成辨认器
    var regressor: CandleModelRegressor = {
        let bundle = Bundle.module
        let url = bundle.url(forResource: "CandleModelRegressor", withExtension:"mlmodelc")!
        return try! CandleModelRegressor(contentsOf: url)
    }()

然后辨认的时分,传入当前k线往前的5个节点的涨跌幅,即可用模型猜测出来一个成果了

        guard let c0 = candleModel.previousCandles[0].rate.double,
              let c1 = candleModel.previousCandles[1].rate.double,
              let c2 = candleModel.previousCandles[2].rate.double,
              let c3 = candleModel.previousCandles[3].rate.double,
              let c4 = candleModel.previousCandles[4].rate.double else {
            throw CommonError(message: "涨跌幅转成double失利")
        }
        logInfo("开端辨认:(c0),(c1),(c2),(c3),(c4)")
        let output = try regressor.prediction(_0: c0, _1: c1, _2: c2, _3: c3, _4: c4)
        logInfo("辨认成果:(output.rate)")

接下来就是买卖的代码了,买卖的代码就不帖了,有爱好大家能够去github自己看,回头我会布置到linux服务上,跑一段时刻,再来看成果,成果也会更新到这里

布置

本来写好了DockerFile准备布置的,之前写一个后台服务都能够成功布置到linux,成果发现这个不可,因为CoreML模块在swift的linux服务端没有,只能跑在macOS了

运用苹果的CoreML来生成一个机器学习的模型,用于测验虚拟币的5分k线的涨跌
正好我有个Mac Mini的Nas服务器,因为没有Mac的docker镜像,所以我就在终端直接运转好了,不关掉这个终端就能一向运转,懒得搞进程看护了

swift run -c release MLTrader

运用苹果的CoreML来生成一个机器学习的模型,用于测验虚拟币的5分k线的涨跌