text: #!/usr/bin/python
  # -*- coding: utf8 -*-
  # cp936
  #
  # The MIT License (MIT)
  #
  # Copyright (c) 2010-2017 fasiondog
  #
  # Permission is hereby granted, free of charge, to any person obtaining a copy
  # of this software and associated documentation files (the "Software"), to deal
  # in the Software without restriction, including without limitation the rights
  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  # copies of the Software, and to permit persons to whom the Software is
  # furnished to do so, subject to the following conditions:
  #
  # The above copyright notice and this permission notice shall be included in all
  # copies or substantial portions of the Software.
  #
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  # SOFTWARE.
  
  #===============================================================================
  # History:
  # 1. 20120926, Added by fasiondog
  #===============================================================================
  
  import urllib
  import sys
  import os
  import configparser
  
  from hikyuu import *
  from hikyuu.indicator import *
  from hikyuu.trade_manage import *
  
  from hikyuu.trade_sys.system import *
  from hikyuu.trade_sys.environment import *
  from hikyuu.trade_sys.condition import *
  from hikyuu.trade_sys.moneymanager import *
  from hikyuu.trade_sys.signal import *
  from hikyuu.trade_sys.stoploss import *
  from hikyuu.trade_sys.profitgoal import *
  from hikyuu.trade_sys.slippage import *
  from hikyuu.trade_sys.selector import *
  from hikyuu.trade_sys.allocatefunds import *
  from hikyuu.trade_sys.portfolio import *
  
  from hikyuu.interactive import *
  #import time
  
  #重定向C++ stdout/stderr输出至python
  #iodog = ostream_redirect()
  iodog = OstreamRedirect()
  iodog.open()
  
  
  #==============================================================================
  # 引入扯线木偶
  #==============================================================================
  #Puppet是一套以同花顺交易客户端为核心的完整的闭环实盘交易系统框架。
  #来自："睿瞳深邃(https://github.com/Raytone-D" 感谢睿瞳深邃的大度共享 :-)
  #可以用：tm.regBroker(crtRB(Puppet())) 的方式注册进tm实例，实现实盘下单
  if sys.platform == 'win32':
      from .puppet import *
  
  
  #==============================================================================
  #
  # 读取配置信息，并初始化
  #
  #==============================================================================
  config_file = os.path.expanduser('~') + "/.hikyuu/hikyuu.ini"
  if not os.path.exists(config_file):
      #检查老版本配置是否存在，如果存在可继续使用，否则异常终止
      data_config_file = os.path.expanduser('~') + "/.hikyuu/data_dir.ini"
      data_config = configparser.ConfigParser()
      data_config.read(data_config_file)
      data_dir = data_config['data_dir']['data_dir']
      if sys.platform == 'win32':
          config_file = data_dir + "\\hikyuu_win.ini"
      else:
          config_file = data_dir + "/hikyuu_linux.ini"
      if not os.path.exists(config_file):
          raise("未找到配置文件，请先使用数据导入工具导入数据（将自动生成配置文件）！！!")
  
  import configparser
  ini = configparser.ConfigParser()
  ini.read(config_file)
  hku_param = Parameter()
  hku_param.set("tmpdir", ini.get('hikyuu', 'tmpdir'))
  if ini.has_option('hikyuu', 'logger'):
      hku_param.set("logger", ini['hikyuu']['logger'])
      
  base_param = Parameter()
  base_info_config = ini.options('baseinfo')
  for p in base_info_config:
      base_param.set(p, ini.get('baseinfo', p))
      
  block_param = Parameter()
  block_config = ini.options('block')
  for p in block_config:
      block_param.set(p, ini.get('block', p))
      
  preload_param = Parameter()
  preload_config = ini.options('preload')
  for p in preload_config:
      #注意：proload参数是布尔类型
      preload_param.set(p, ini.getboolean('preload', p))
      
  kdata_param = Parameter()
  kdata_config = ini.options('kdata')
  for p in kdata_config:
      kdata_param.set(p, ini.get('kdata', p))
  
  set_log_level(LOG_LEVEL.TRACE)
  sm = StockManager.instance()
  sm.init(base_param, block_param, kdata_param, preload_param, hku_param)
  set_log_level(LOG_LEVEL.WARN)
  
  
  #==============================================================================
  #
  # 引入blocka、blocksh、blocksz、blockg全局变量，便于交互式环境下使用
  #
  #==============================================================================
  
  blocka = Block("A", "ALL")
  for s in sm:
      if s.type in (constant.STOCKTYPE_A, constant.STOCKTYPE_GEM):
          blocka.add(s)
  zsbk_a = blocka
  
  blocksh = Block("A", "SH")
  for s in blocka:
      if s.market == "SH":
          blocksh.add(s)
  zsbk_sh = blocksh
  
  blocksz = Block("A", "SZ")
  for s in blocka:
      if s.market == "SZ":
          blocksz.add(s)
  zsbk_sz = blocksz
  
  blockg = Block("G", "创业板")
  for s in sm:
      if s.type == constant.STOCKTYPE_GEM:
          blockg.add(s)
  zsbk_cyb = blockg
  
  blockzxb = Block("A", "中小板")
  for s in blocksz:
      if s.code[:3] == "002":
          blockzxb.add(s) 
  zsbk_zxb = blockzxb
  
  zsbk_sz50 = sm.getBlock("指数板块", "上证50")
  zsbk_sz180 = sm.getBlock("指数板块", "上证180")
  zsbk_hs300 = sm.getBlock("指数板块", "沪深300")
  zsbk_zz100 = sm.getBlock("指数板块", "沪深300")
  
  
  #==============================================================================
  #
  # 设置关键类型简称
  #
  #==============================================================================            
  O = OPEN
  C = CLOSE
  H = HIGH
  L = LOW
  A = AMO
  V = VOL
  D = Datetime
  K = None
  
  def set_global_context(stk, query):
      """设置全局的 context
  
          :param Stock stk: 指定的全局Stock
          :param Query query: 指定的查询条件
      """
      global K, O, C, H, L, A, V
      K = stk.getKData(query)
      O.setContext(K)
      C.setContext(K)
      H.setContext(K)
      L.setContext(K)
      A.setContext(K)
      V.setContext(K)
  
  
  def get_global_context():
      """获取当前的全局上下文
      
          :rtype: KData
      """
      return C.getContext()    
  
  set_global_context(sm['sh000001'], Query(-150))
  
  
  #==============================================================================
  #
  # 设置默认绘图引擎
  #
  #==============================================================================            
  
  use_draw_engine('matplotlib')
  
  
  #==============================================================================
  #
  # 粗略的选股函数
  #
  #==============================================================================            
  
  def select(cond, start=Datetime(201801010000), end=Datetime.now(), print_out=True):
      """
      示例：
      #选出涨停股
      C = CLOSE()
      x = select(C / REF(C, 1) - 1 >= 0.0995))
  
      :param Indicator cond: 条件指标
      :param Datetime start: 起始日期
      :param Datetime end: 结束日期
      :param bool print_out: 打印选中的股票
      :rtype: 选中的股票列表
      """
      q = QueryByDate(start, end)
      d = sm.getTradingCalendar(q, 'SH')
      if len(d) == 0:
          return
  
      result = []
      for s in blocka:
          if not s.valid:
              continue
          
          q = QueryByDate(start, end)
          k = s.getKData(q)
          cond.setContext(k)
          if len(cond) > 0 and cond[-1] != constant.null_price and cond[-1] > 0 and len(k) > 0 and k[-1].datetime == d[-1]:
              result.append(s)
              if print_out:
                  print(d[-1], s)
                  
      return result
  
  
  #==============================================================================
  #
  # 增加临时的实时数据更新函数 realtimeUpdate
  #
  #==============================================================================
  
  def UpdateOneRealtimeRecord_from_sina(tmpstr):
      try:
          if len(tmpstr) > 3 and tmpstr[:3] == 'var':
              a = tmpstr.split(',')
              if len(a) < 9:
                  return
              
              open, close, high, low = float(a[1]), float(a[3]), float(a[4]), float(a[5])
              transamount = float(a[9])
              transcount = float(a[8])
                  
              d = Datetime(a[-3]+" 00")
              temp = (open, high, low, close)
              if 0 in temp:
                  return
  
              stockstr = a[0].split('=')
              stock = sm[stockstr[0][-8:]]
              
              record = KRecord()
              record.datetime = d
              record.openPrice = open
              record.highPrice = high
              record.lowPrice = low
              record.closePrice = close
              record.transAmount = transamount
              record.transCount = transcount/100
  
              stock.realtimeUpdate(record)
      
      except Exception as e:
          print(tmpstr)
          print(e)
  
  def UpdateOneRealtimeRecord_from_qq(tmpstr):
      try:
          if len(tmpstr) > 3 and tmpstr[:2] == 'v_':
              a = tmpstr.split('~')
              if len(a) < 9:
                  return
              
              open, close, high, low = float(a[5]), float(a[3]), float(a[33]), float(a[34])
              transamount = float(a[36])
              transcount = float(a[37])
                  
              d = Datetime(int(a[30][:8] + '0000'))
              temp = (open, high, low, close)
              if 0 in temp:
                  return
  
              stockstr = a[0].split('=')
              stock = sm[stockstr[0][-8:]]
              
              record = KRecord()
              record.datetime = d
              record.openPrice = open
              record.highPrice = high
              record.lowPrice = low
              record.closePrice = close
              record.transAmount = transamount
              record.transCount = transcount/100
  
              stock.realtimeUpdate(record)
      
      except Exception as e:
          print(tmpstr)
          print(e)
          
  def realtimePartUpdate_from_sina(queryStr):
      result = urllib.request.urlopen(queryStr).read()
      try:
          result = result.decode('gbk')
      except Exception as e:
          print(result)
          print(e)
          return
      
      result = result.split('\n')
      for tmpstr in result:
          UpdateOneRealtimeRecord_from_sina(tmpstr)
          
  def realtimePartUpdate_from_qq(queryStr):
      result = urllib.request.urlopen(queryStr).read()
      try:
          result = result.decode('gbk')
      except Exception as e:
          print(result)
          print(e)
          return
      
      result = result.split('\n')
      for tmpstr in result:
          UpdateOneRealtimeRecord_from_qq(tmpstr)
                  
  def realtimeUpdate_from_sina_qq(source):
      if source == 'sina':
          queryStr = "http://hq.sinajs.cn/list=" 
          update_func = realtimePartUpdate_from_sina
          max_size = 140
      elif source == 'qq':
          queryStr = "http://qt.gtimg.cn/q="
          update_func = realtimePartUpdate_from_qq
          max_size = 60
      else:
          print('Not support!')
          return
          
      count  = 0
      urls = []
      tmpstr = queryStr
      for stock in sm:
          if stock.valid and stock.type in (constant.STOCKTYPE_A, 
                                            constant.STOCKTYPE_INDEX,
                                            constant.STOCKTYPE_ETF, 
                                            constant.STOCKTYPE_GEM):
              tmpstr += ("%s,") % (stock.market_code.lower())
              count = count + 1
              if count >= max_size:
                  #urls.append(tmpstr)
                  update_func(tmpstr)
                  count = 0
                  tmpstr = queryStr
  
      if tmpstr != queryStr:
          #urls.append(tmpstr)
          update_func(tmpstr)
     
      #不用并行，防止过快，ip被网站屏蔽
      #from multiprocessing import Pool
      #from multiprocessing.dummy import Pool as ThreadPool
      #pool = ThreadPool()
      #if source == 'sina':
      #    pool.map(realtimePartUpdate_from_sina, urls)
      #else:
      #    pool.map(realtimePartUpdate_from_qq, urls)
      #pool.close()
      #pool.join()
  
      
  def realtimeUpdate_from_tushare():
      import tushare as ts
      
      #更新股票行情
      df = ts.get_today_all()
      for i in range(len(df)):
          if df.ix[i, 'open'] == 0:
              continue  #停牌
          
          code = df.ix[i][0]
          stock = getStock('sh' + code)
          
          if stock.isNull() == True or stock.type != constant.STOCKTYPE_A:
              stock = getStock('sz' + code)
          if stock.isNull() == True:
              continue
          
          record = KRecord()
          record.openPrice = df.ix[i, 'open']
          record.highPrice = df.ix[i, 'high']
          record.lowPrice = df.ix[i, 'low']
          record.closePrice = df.ix[i, 'trade']
          record.transAmount = float(df.ix[i, 'amount'])
          record.transCount = float(df.ix[i, 'volume'])
          
          from datetime import date
          d = date.today()
          record.datetime = Datetime(d)
          stock.realtimeUpdate(record)
          
      #更新指数行情
      df = ts.get_index()
      for i in range(len(df)):
          code = df.ix[i][0]
          stock = getStock('sh' + code)
          if stock.isNull() == True or stock.type != constant.STOCKTYPE_INDEX:
              stock = getStock('sz' + code)
          if stock.isNull() == True:
              continue
          
          total = stock.getCount(Query.DAY)
          if total == 0:
              continue
              
          last_record = stock.getKRecord(total - 1)
          
          record = KRecord()
          record.openPrice = df.ix[i, 'open']
          record.highPrice = df.ix[i, 'high']
          record.lowPrice = df.ix[i, 'low']
          record.closePrice = df.ix[i, 'close']
          record.transCount = float(df.ix[i, 'volume'])
          record.transAmount = float(df.ix[i, 'amount'])
          
          if (last_record.closePrice != record.closePrice 
                  or last_record.highPrice != record.highPrice 
                  or last_record.lowPrice != record.lowPrice
                  or last_record.openPrice != record.openPrice):
              from datetime import date
              d = date.today()
              record.datetime = Datetime(d)
              stock.realtimeUpdate(record)
  
  def realtimeUpdate_inner(source='tushare'):
      if source == 'sina' or source == 'qq':
          realtimeUpdate_from_sina_qq(source)
      elif source == 'tushare':
          realtimeUpdate_from_tushare()
      else:
          print(source, ' not support!')
          
          
  def realtimeUpdateWrap():
      pre_update_time = None
      def realtimeUpdate_closure(source='tushare', delta=60):
          """
          更新实时日线数据
          参数：
              source: 数据源（'sina' | 'qq' | 'tushare'）
              delta: 更新间隔时间
          """
          from datetime import timedelta, datetime
          nonlocal pre_update_time
          now_update_time = datetime.now()
          if (pre_update_time is None) or (now_update_time - pre_update_time) > timedelta(0, delta, 0):
              realtimeUpdate_inner(source)
              pre_update_time = datetime.now()
              print("更新完毕！", pre_update_time)
          else:
              print("更新间隔小于" + str(delta) + "秒，未更新")
              print("上次更新时间: ", pre_update_time)  
      return realtimeUpdate_closure
  
  realtimeUpdate = realtimeUpdateWrap()
              
  
  