text: # -*- coding: utf-8 -*-
  """
  -------------------------------------------------
     File Name：     1
     Description :
     Author :        mixbe
     date：          2020/10/16
  -------------------------------------------------
     Change Activity:
                     2020/10/16:
  -------------------------------------------------
  """
  
  # 克隆自聚宽文章：https://www.joinquant.com/post/1810
  # 标题：【量化课堂】基于协整的搬砖策略
  # 作者：JoinQuant量化课堂
  
  import numpy as np
  import pandas as pd
  
  
  # ===========================================
  
  def init(context):
      set_params()
      set_variables()
      #set_backtest()
  
  
  # ---代码块1. 设置参数
  def set_params():
      # 股票1
      g.security1 = '600887.XSHG'
      # 股票2
      g.security2 = '600036.XSHG'
      # 基准
      g.benchmark = '600036.XSHG'
      # 回归系数
      g.regression_ratio = 1.000  # 0.9574#0.9938
      # 股票1默认仓位
      g.p = 0.5
      # 股票2默认仓位
      g.q = 0.5
      # 算z-score天数
      g.test_days = 120
  
  
  # ---代码块2. 设置变量
  def set_variables():
      # 现在状态
      g.state = 'empty'
  
  
  # ---代码块3. 设置回测
  def set_backtest():
      # 设置基准
      set_benchmark(g.benchmark)
      # 只报错
      log.set_level('order', 'error')
      # 真实价格
      set_option('use_real_price', True)
      # 无滑点
      set_slippage(FixedSlippage(0.))
  
  
  # ==============================================
  
  # 每个单位时间(如果按天回测,则每天调用一次,如果按分钟,则每分钟调用一次)调用一次
  def handle_bar(context, data):
      new_state = get_signal()
      change_positions(new_state, context)
  
  
  # ---代码块4.计算z-score
  def z_test():
      # 获取两支股票历史价格
      # prices1 = np.array(attribute_history(g.security1, g.test_days, '1d', ['close']).close)
      # prices2 = np.array(attribute_history(g.security2, g.test_days, '1d', ['close']).close)
      prices1 = np.array(get_bars(g.security1, g.test_days, '1d', ['close']).close)
      prices2 = np.array(get_bars(g.security2, g.test_days, '1d', ['close']).close)
  
      # 根据回归比例算它们的平稳序列 Y-a.X
      stable_series = prices2 - g.regression_ratio * prices1
      # 算均值
      series_mean = np.mean(stable_series)
      # 算标准差
      sigma = np.std(stable_series)
      # 算序列现值离均值差距多少
      diff = stable_series[-1] - series_mean
      # 返回z值
      return (diff / sigma)
  
  
  # ---代码块5.获取信号
  # 返回新的状态，是一个string
  def get_signal():
      z_score = z_test()
      if z_score > 1:
          # 状态为全仓第一支
          return ('buy1')
      # 如果小于负标准差
      if z_score < -1:
          # 状态为全仓第二支
          return ('buy2')
      # 如果在正负标准差之间
      if -1 <= z_score <= 1:
          # 如果差大于0
          if z_score >= 0:
              # 在均值上面
              return ('side1')
          # 反之
          else:
              # 在均值下面
              return ('side2')
  
  
  # ---代码块6.根据信号调换仓位
  # 输入是目标状态，输入为一个string
  def change_positions(new_state, context):
      # 总值产价值
      total_value = context.portfolio.portfolio_value
      # 如果新状态是全仓股票1
      if new_state == 'buy1':
          # 全卖股票2
          order_percent(g.security2, -1)
          # 全买股票1
          order_value(g.security1, total_value)
          # 旧状态更改
          g.state = 'buy1'
      # 如果新状态是全仓股票2
      if new_state == 'buy2':
          # 全卖股票1
          order_percent(g.security1, -1)
          # 全买股票2
          order_value(g.security2, total_value)
          # 旧状态更改
          g.state = 'buy2'
      # 如果处于全仓一股票状态，但是z-score交叉0点
      if (g.state == 'buy1' and new_state == 'side2') or (g.state == 'buy2' and new_state == 'side1'):
          # 按照p,q值将股票仓位调整为默认值
          order_target_value(g.security1, g.p * total_value)
          order_target_value(g.security2, g.q * total_value)
          # 代码里重复两遍因为要先卖后买，而我们没有特地确定哪个先哪个后
          order_target_value(g.security1, g.p * total_value)
          order_target_value(g.security2, g.q * total_value)
          # 状态改为‘平’
          g.state = 'even'
  CONFIG = {
      "base": {
          "start_date": "20190101",
          "end_date": "20200901",
          "frequency": "1d",
          # "benchmark": "000300.XSHG",
          "accounts": {
              "STOCK": 10e8
          }
      },
      "extra": {
          "log_level": "verbose"
      },
      "mod": {
          "sys_analyser": {
              "enabled": True,
              # "report_save_path": ".",
              "plot": True,
              "enabled": True,
              "benchmark": "000300.XSHG"
              # "matching_type": "last"
          },
      }
  }
  
  
  if __name__ == "__main__":
      from jqdatasdk import *
      auth('18332556055','cjl011235813')
      from rqalpha import run_func
      run_func(init=init, handle_bar=handle_bar, config=CONFIG)
  