[
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*,cover\n.hypothesis/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n#Ipython Notebook\n.ipynb_checkpoints\n"
  },
  {
    "path": "README.md",
    "content": "# easyhistory\n用于获取维护股票的历史数据\n\n### 引入\n\n```python\nimport easyhistory\n```\n\n### 读取 rqalpha 保存的历史数据\n\n读取平安银行\n\n```python\neasyhistory.history('000001') \n\nreturn pandas dataframe: \n                  open   close    high     low    volume  total_turnover  \\\ndatetime\n20050104000000  1.6668  1.6491  1.6668  1.6338   6961738        11465602\n20050105000000  1.6491  1.6338  1.6567  1.6061  12739274        20718558\n20050106000000  1.6440  1.6491  1.6668  1.6314  10542101        17333840\n20050107000000  1.6643  1.6466  1.6693  1.6338   7457207        12302853\n20050110000000  1.6466  1.6668  1.6668  1.6112  10406261        17111498\n\n                limit_up  limit_down\ndatetime\n20050104000000    1.8337      1.4999\n20050105000000    1.8135      1.4846\n20050106000000    1.7983      1.4695\n20050107000000    1.8135      1.4846\n20050110000000    1.8110      1.4822\n```\n\n读取上证指数\n\n```python\neasyhistory.history('000001', market='sh')\n```\n\n### 初始化日线历史数据\n\n```python\neasyhistory.init('D', export='csv', path='history')\n```\n\n注1： 下载后的原始数据在 `path/day/raw_data` 下, 复权后数据在  `path/day/data` 下\n\n注2: 下载所有股票的历史数据需要很长时间，推荐直接从[百度盘](http://pan.baidu.com/s/1o7rwH0e)(数据到 20160318 )下载, \n\n### 更新\n\n```python\neasyhistory.update('D', export='csv', path='history')\n```\n\n### 指标系统\n\n目前还在测试中，指标计算使用了 `talib` 和 `pandas`, 可以直接调用 `talib` 计算一百多种指标，包括 `MACD, EMA, MA` 等\n\n* tablib 安装: https://github.com/mrjbq7/ta-lib\n* pandas: pip install pandas\n\n#### 使用\n\n```python\nhis = easyhistory.History(dtype='D', path='行情目录')\n\n# MA 计算, 直接调用的 talib 的对应函数\nres = his['000001'].MA(5)\n\n\n# 返回的是 pandas 的 dataframe 格式\n\n             open   high  close    low     volume      amount  factor     MA5\ndate                                                                         \n2016-03-10  10.24  10.35  10.15  10.13  506112.94  5193459.68  93.659  10.268\n2016-03-11  10.10  10.22  10.16  10.04  409716.87  4160186.89  93.659  10.220\n\n```\n\n注: [talib 可用指标以及相关参数](https://github.com/mrjbq7/ta-lib) 以及 [pandas 相关](https://github.com/pydata/pandas)\n\n\n### Q&A\n\nQ:安装 `talib` 提示找不到 `vcvarsall.bat` ?\nA: 去 `http://www.lfd.uci.edu/~gohlke/pythonlibs` 下载 `wheels`版本的包使用 `pip install xxx.whl` 安装\n"
  },
  {
    "path": "easyhistory/__init__.py",
    "content": "# coding:utf-8\nfrom .api import *\n\n__version__ = '0.0.1'\n"
  },
  {
    "path": "easyhistory/api.py",
    "content": "# coding:utf-8\nfrom rqalpha.data.base_data_source import BaseDataSource\nimport pandas as pd\nimport easyutils\nimport datetime\nimport os\n\nfrom .day import Day\n\n\ndef init(dtype='D', export='csv', path='history'):\n    return Day(path=path, export=export).init()\n\n\ndef update_single_code(dtype='D', stock_code=None, path='history', export='csv'):\n    if stock_code is None:\n        raise Exception('stock code is None')\n    return Day(path=path, export=export).update_single_code(stock_code)\n\n\ndef update(dtype='D', export='csv', path='history'):\n    return Day(path=path, export=export).update()\n\n\ndef history(stock_code, market=None, bundle_path='~/.rqalpha/bundle'):\n    d = BaseDataSource(os.path.expanduser(bundle_path))\n\n    instruments = d._instruments.get_all_instruments()\n\n    stock_map = {i.order_book_id: i for i in instruments}\n    if not market:\n        market = easyutils.get_stock_type(stock_code)\n    if market == 'sh':\n        stock_code += '.XSHG'\n    else:\n        stock_code += '.XSHE'\n    raw = d._all_day_bars_of(stock_map[stock_code])\n    df = pd.DataFrame.from_dict(raw)\n    df.set_index('datetime', inplace=True)\n    return df\n\n#\n"
  },
  {
    "path": "easyhistory/day.py",
    "content": "# coding: utf-8\nimport math\nimport re\nimport time\nfrom datetime import datetime\nfrom datetime import timedelta\nfrom multiprocessing.pool import ThreadPool\n\nimport requests\nfrom pyquery import PyQuery\n\nfrom . import helpers\nfrom . import store\n\n\nclass Day:\n    SINA_API = 'http://vip.stock.finance.sina.com.cn/corp/go.php/vMS_FuQuanMarketHistory/stockid/{stock_code}.phtml'\n    SINA_API_HOSTNAME = 'vip.stock.finance.sina.com.cn'\n    STOCK_CODE_API = 'http://218.244.146.57/static/all.csv'\n\n    def __init__(self, path='history', export='csv'):\n        self.store = store.use(export=export, path=path, dtype='D')\n\n    def init(self):\n        stock_codes = self.store.init_stock_codes\n        pool = ThreadPool(10)\n        pool.map(self.init_stock_history, stock_codes)\n\n    def update(self):\n        \"\"\" 更新已经下载的历史数据 \"\"\"\n        stock_codes = self.store.update_stock_codes\n        pool = ThreadPool(2)\n        pool.map(self.update_single_code, stock_codes)\n\n    def update_single_code(self, stock_code):\n        \"\"\" 更新对应的股票文件历史行情\n        :param stock_code: 股票代码\n        :return:\n        \"\"\"\n        latest_date = self.store.get_his_stock_date(stock_code)\n        updated_data = self.get_update_day_history(stock_code, latest_date)\n        \n        if len(updated_data) == 0 or len(updated_data[0]) == 0:\n            return \n\n        self.store.write(stock_code, updated_data)\n\n    def get_update_day_history(self, stock_code, latest_date):\n        data_year = latest_date.year\n        data_quarter = helpers.get_quarter(latest_date.month)\n        now_year = datetime.now().year\n        # 使用下一天的日期作为更新起始日，避免季度末时多更新上一季度的内容\n        tomorrow = datetime.now() + timedelta(days=1)\n        now_quarter = helpers.get_quarter(tomorrow.month)\n\n        updated_data = list()\n        for year in range(data_year, now_year + 1):\n            for quarter in range(1, 5):\n                if year == data_year:\n                    if quarter < data_quarter:\n                        continue\n                if year == now_year:\n                    if quarter > now_quarter:\n                        continue\n                # if year == now_year:\n                #     if quarter > now_quarter:\n                #         continue\n                # elif year == data_year:\n                #     if quarter < data_quarter:\n                #         continue\n                updated_data += self.get_quarter_history(stock_code, year, quarter)\n        updated_data.sort(key=lambda day: day[0])\n        return updated_data\n\n    def init_stock_history(self, stock_code):\n        all_history = self.get_all_history(stock_code)\n        if len(all_history) <= 0:\n            return\n        self.store.write(stock_code, all_history)\n\n    def get_all_history(self, stock_code):\n        years = self.get_stock_time(stock_code)\n        all_history = []\n        for year in years:\n            year_history = self.get_year_history(stock_code, year)\n            all_history += year_history\n        all_history.sort(key=lambda day: day[0])\n        return all_history\n\n    def get_year_history(self, stock_code, year):\n        year_history = []\n        now_year = datetime.now().year\n        now_month = datetime.now().month\n        end_quarter = 5 if str(year) != str(now_year) else math.ceil(now_month / 3) + 1\n        for quarter in range(1, end_quarter):\n            quarter_data = self.get_quarter_history(stock_code, year, quarter)\n            if quarter_data is None:\n                continue\n            year_history += quarter_data\n        return year_history\n\n    def get_stock_time(self, stock_code):\n        # 获取年月日\n        url = self.SINA_API.format(stock_code=stock_code)\n        try:\n            dom = PyQuery(url)\n        except requests.ConnectionError:\n            return []\n        year_options = dom('select[name=year] option')\n        years = [o.text for o in year_options][::-1]\n        return years\n\n    def get_quarter_history(self, stock_code, year, quarter):\n        year = int(year)\n        if year < 1990:\n            return list()\n        params = dict(\n                year=year,\n                jidu=quarter\n        )\n        headers = {\n            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko'\n        }\n        print('request {},{},{}'.format(stock_code, year, quarter))\n        url = self.SINA_API.format(stock_code=stock_code)\n        rep = list()\n        loop_nums = 10\n        for i in range(loop_nums):\n            try:\n                rep = requests.get(url, params, timeout=3, headers=headers)\n                break\n            except requests.ConnectionError:\n                time.sleep(60)\n            except Exception as e:\n                with open('error.log', 'a+') as f:\n                    f.write(str(e))\n\n        print('end request {}, {}, {}'.format(stock_code, year, quarter))\n        if rep is None:\n            with open('error.txt', 'a+') as f:\n                f.write('{},{},{}'.format(stock_code, year, quarter))\n            return list()\n        res = self.handle_quarter_history(rep.text)\n        return res\n\n    def handle_quarter_history(self, rep_html):\n        dom = PyQuery(rep_html)\n        raw_trows = dom('#FundHoldSharesTable tr')\n        empty_history_nodes = 2\n        if len(raw_trows) <= empty_history_nodes:\n            return list()\n\n        unused_head_index_end = 2\n        trows = raw_trows[unused_head_index_end:]\n\n        res = list()\n        for row_td_list in trows:\n            td_list = row_td_list.getchildren()\n            day_history = []\n            for i, td in enumerate(td_list):\n                td_content = td.text_content()\n                date_index = 0\n                if i == date_index:\n                    td_content = re.sub(r'\\r|\\n|\\t', '', td_content)\n                day_history.append(td_content)\n            self.convert_stock_data_type(day_history)\n            res.append(day_history)\n        return res\n\n    def convert_stock_data_type(self, day_data):\n        \"\"\"将获取的对应日期股票数据除了日期之外，转换为正确的 float / int 类型\n        :param day_data: ['2016-02-19', '945.019', '949.701', '940.336', '935.653', '31889824.000', '320939648.000', '93.659']\n        :return: ['2016-02-19', 945.019, 949.701, 940.336, 935.653, 31889824.000, 320939648.000, 93.659]\n        \"\"\"\n        date_index = 0\n        for i, val in enumerate(day_data):\n            if i == date_index:\n                continue\n            day_data[i] = float(val)\n"
  },
  {
    "path": "easyhistory/helpers.py",
    "content": "# coding:utf-8\nimport math\n\n\ndef get_quarter(month):\n    return math.ceil(int(month) / 3)\n"
  },
  {
    "path": "easyhistory/history.py",
    "content": "# coding:utf-8\nimport os\n\nimport pandas as pd\nimport talib\n\n\nclass Indicator(object):\n    def __init__(self, stock_code, history):\n        self.stock_code = stock_code\n        self.history = history\n        self.hisarg = {}\n\n    def load_csv_files(self, path):\n        file_list = [f for f in os.listdir(path) if f.endswith('.csv')]\n        for stock_csv in file_list:\n            csv_ext_index_start = -4\n            stock_code = stock_csv[:csv_ext_index_start]\n            self.market[stock_code] = pd.read_csv(stock_csv, index_col='date')\n\n    def __getattr__(self, item):\n        def talib_func(*args, **kwargs):\n            str_args = ''.join(map(str, args))\n            index = item + str_args\n            if index in self.hisarg and self.hisarg[index] is not None:\n                return self.hisarg[index]\n            func = getattr(talib, item)\n            res_arr = func(self.history['close'].values, *args, **kwargs)\n            self.hisarg[index] = res_arr\n            return self.hisarg[index]\n\n        return talib_func\n\n\nclass History(object):\n    def __init__(self, dtype='D', path='history', stock=None):\n        self.market = dict()\n        data_path = os.path.join(path, 'day', 'data')\n        self.load_csv_files(data_path, stock)\n\n    def load_csv_files(self, path, stock=None):\n        if stock and os.path.exists( os.path.join(path, stock+'.csv') ):\n            stock_csv = stock+'.csv'\n            stock_code = stock\n            csv_path = os.path.join(path, stock_csv)\n            self.market[stock_code] = Indicator(stock_code, pd.read_csv(csv_path, index_col='date'))\n            return\n\n        file_list = [f for f in os.listdir(path) if f.endswith('.csv')]\n        for stock_csv in file_list:\n            csv_ext_index_start = -4\n            stock_code = stock_csv[:csv_ext_index_start]\n\n            csv_path = os.path.join(path, stock_csv)\n            self.market[stock_code] = Indicator(stock_code, pd.read_csv(csv_path, index_col='date'))\n\n    def __getitem__(self, item):\n        return self.market[item]\n"
  },
  {
    "path": "easyhistory/store.py",
    "content": "# coding: utf8\nimport json\nimport os\nfrom datetime import datetime\n\nimport easyutils\nimport pandas as pd\n\n\ndef use(export='csv', **kwargs):\n    if export.lower() in ['csv']:\n        return CSVStore(**kwargs)\n\n\nclass Store:\n    def load(self, stock_data):\n        pass\n\n    def write(self, stock_code, data):\n        pass\n\n\nclass CSVStore(Store):\n    def __init__(self, path, dtype):\n        if dtype.lower() in ['d']:\n            self.path = os.path.join(path, 'day')\n        self.result_path = os.path.join(self.path, 'data')\n        self.raw_path = os.path.join(self.path, 'raw_data')\n\n    def write(self, stock_code, updated_data):\n        if not os.path.exists(self.result_path):\n            os.makedirs(self.result_path)\n        if not os.path.exists(self.raw_path):\n            os.makedirs(self.raw_path)\n\n        csv_file_path = os.path.join(self.raw_path, '{}.csv'.format(stock_code))\n        if os.path.exists(csv_file_path):\n            try:\n                his = pd.read_csv(csv_file_path)\n            except ValueError:\n                return\n\n            updated_data_start_date = updated_data[0][0]\n            old_his = his[his.date < updated_data_start_date]\n            updated_his = pd.DataFrame(updated_data, columns=his.columns)\n            his = old_his.append(updated_his)\n        else:\n            his = pd.DataFrame(updated_data,\n                               columns=['date', 'open', 'high', 'close', 'low', 'volume', 'amount', 'factor'])\n        his.to_csv(csv_file_path, index=False)\n        date = his.iloc[-1].date\n        self.write_summary(stock_code, date)\n        self.write_factor_his(stock_code, his)\n\n    def get_his_stock_date(self, stock_code):\n        summary_path = os.path.join(self.raw_path, '{}_summary.json'.format(stock_code))\n        with open(summary_path) as f:\n            summary = json.load(f)\n        latest_date = datetime.strptime(summary['date'], '%Y-%m-%d')\n        return latest_date\n\n    def write_summary(self, stock_code, date):\n        file_path = os.path.join(self.raw_path, '{}_summary.json'.format(stock_code))\n        with open(file_path, 'w') as f:\n            latest_day = datetime.strptime(date, '%Y-%m-%d')\n            summary = dict(\n                    year=latest_day.year,\n                    month=latest_day.month,\n                    day=latest_day.day,\n                    date=date\n            )\n            json.dump(summary, f)\n\n    def write_factor_his(self, stock_code, his):\n        result_file_path = os.path.join(self.result_path, '{}.csv'.format(stock_code))\n        factor_cols = his.columns.difference(['date'])\n        his[factor_cols] = his[factor_cols] / his.factor.max()\n        his.to_csv(result_file_path, index=False)\n\n    @property\n    def init_stock_codes(self):\n        stock_codes = easyutils.stock.get_all_stock_codes()\n        exists_codes = set()\n        if os.path.exists(self.raw_path):\n            code_slice = slice(-4)\n            exists_codes = {code[code_slice] for code in os.listdir(self.raw_path) if code.endswith('.csv')}\n        return set(stock_codes).difference(exists_codes)\n\n    @property\n    def update_stock_codes(self):\n        code_slice = slice(6)\n        return [f[code_slice] for f in os.listdir(self.raw_path) if f.endswith('.json')]\n"
  },
  {
    "path": "requirements.txt",
    "content": "requests\npandas\neasyutils\n\n"
  },
  {
    "path": "setup.py",
    "content": "# coding:utf8\r\nfrom setuptools import setup\r\n\r\nimport easyhistory\r\n\r\nlong_desc = \"\"\"\r\neasyhistory\r\n===============\r\n\r\n* easy to use rqalpha history data\r\n\r\nInstallation\r\n--------------\r\n\r\npip install easytrader\r\n\r\nUpgrade\r\n---------------\r\n\r\n    pip install easytrader --upgrade\r\n\"\"\"\r\n\r\nsetup(\r\n    name='easyhistory',\r\n    version=easyhistory.__version__,\r\n    description='A utility for rqalpha history',\r\n    long_description=long_desc,\r\n    author='shidenggui',\r\n    author_email='longlyshidenggui@gmail.com',\r\n    license='BSD',\r\n    url='https://github.com/shidenggui/easyhistory',\r\n    keywords='China stock trade',\r\n    install_requires=[\r\n            'rqalpha',\r\n            'requests',\r\n            'six',\r\n            'easyutils',\r\n    ],\r\n    classifiers=['Development Status :: 4 - Beta',\r\n                 'Programming Language :: Python :: 2.6',\r\n                 'Programming Language :: Python :: 2.7',\r\n                 'Programming Language :: Python :: 3.2',\r\n                 'Programming Language :: Python :: 3.3',\r\n                 'Programming Language :: Python :: 3.4',\r\n                 'Programming Language :: Python :: 3.5',\r\n                 'License :: OSI Approved :: BSD License'],\r\n    packages=['easyhistory'],\r\n    package_data={},\r\n)\r\n"
  },
  {
    "path": "test.py",
    "content": "import easyhistory\n\neasyhistory.update()\n\n"
  },
  {
    "path": "test_history.py",
    "content": "import unittest\nfrom datetime import datetime\n\nimport easyhistory\n\n\nclass TestHistory(unittest.TestCase):\n    def test_get_history(self):\n        test_date = '000001'\n        normal_data = [str(y) for y in range(1991, datetime.now().year + 1)]\n        res = easyhistory.Day().get_stock_time(test_date)\n\n        self.assertListEqual(res, normal_data)\n\n    def test_get_quarter_history(self):\n        test_data = ['000001', 2016, 1]\n        normal_data = [['2016-03-31', 1003.087, 1006.833, 996.53, 996.53, 41838792.0, 447266272.0, 93.659],\n                       ['2016-03-30', 981.545, 1002.15, 1002.15, 980.608, 53970000.0, 572627392.0, 93.659],\n                       ['2016-03-29', 984.354, 985.291, 976.862, 972.179, 31831788.0, 332422400.0, 93.659],\n                       ['2016-03-28', 994.657, 997.466, 981.544, 978.735, 35862100.0, 378973312.0, 93.659],\n                       ['2016-03-25', 984.354, 992.783, 991.847, 983.417, 23707048.0, 250338496.0, 93.659],\n                       ['2016-03-24', 993.72, 995.593, 985.291, 983.417, 37240624.0, 393411552.0, 93.659],\n                       ['2016-03-23', 1003.085, 1008.705, 1002.149, 993.72, 43027816.0, 458963264.0, 93.659],\n                       ['2016-03-22', 1008.705, 1024.627, 1004.022, 1001.213, 62548248.0, 675406592.0, 93.659],\n                       ['2016-03-21', 988.1, 1017.134, 1011.515, 988.1, 92043280.0, 987764480.0, 93.659],\n                       ['2016-03-18', 975.924, 989.973, 987.163, 974.051, 79721584.0, 836565568.0, 93.659],\n                       ['2016-03-17', 970.305, 981.544, 975.925, 964.685, 61099640.0, 635181312.0, 93.659],\n                       ['2016-03-16', 961.876, 978.735, 969.369, 960.003, 66488620.0, 690087744.0, 93.659],\n                       ['2016-03-15', 962.813, 970.305, 966.559, 951.573, 41792036.0, 428786688.0, 93.659],\n                       ['2016-03-14', 956.256, 979.671, 960.939, 956.256, 65515824.0, 679161280.0, 93.659],\n                       ['2016-03-11', 945.953, 957.192, 951.573, 940.334, 38373672.0, 389638944.0, 93.659],\n                       ['2016-03-10', 959.066, 969.368, 950.637, 948.763, 47402032.0, 486414240.0, 93.659],\n                       ['2016-03-09', 949.7, 957.193, 952.51, 940.334, 32590064.0, 330124896.0, 93.659],\n                       ['2016-03-08', 970.305, 970.305, 962.812, 930.968, 64315648.0, 650471616.0, 93.659],\n                       ['2016-03-07', 969.369, 982.481, 968.432, 964.686, 60635296.0, 630155584.0, 93.659],\n                       ['2016-03-04', 945.017, 983.417, 974.051, 943.144, 138124912.0, 1429273088.0, 93.659],\n                       ['2016-03-03', 945.018, 953.447, 946.891, 940.335, 55308940.0, 559045184.0, 93.659],\n                       ['2016-03-02', 913.174, 948.764, 945.954, 910.364, 67661376.0, 673626240.0, 93.659],\n                       ['2016-03-01', 900.998, 915.047, 908.491, 897.252, 37791080.0, 365149024.0, 93.659],\n                       ['2016-02-29', 916.92, 918.794, 895.379, 882.267, 56689640.0, 542184000.0, 93.659],\n                       ['2016-02-26', 915.047, 920.666, 916.92, 904.744, 39215440.0, 382634656.0, 93.659],\n                       ['2016-02-25', 947.827, 948.764, 905.681, 899.124, 62207284.0, 615004736.0, 93.659],\n                       ['2016-02-24', 942.208, 950.637, 950.637, 937.525, 30010360.0, 302498016.0, 93.659],\n                       ['2016-02-23', 963.75, 963.75, 947.828, 941.272, 42587436.0, 432315296.0, 93.659],\n                       ['2016-02-22', 948.764, 965.623, 963.75, 942.208, 61773944.0, 630251520.0, 93.659],\n                       ['2016-02-19', 945.019, 949.701, 940.336, 935.653, 31889824.0, 320939648.0, 93.659],\n                       ['2016-02-18', 953.448, 957.194, 945.018, 945.018, 40617824.0, 412337568.0, 93.659],\n                       ['2016-02-17', 939.398, 957.194, 950.637, 935.652, 58516704.0, 590538944.0, 93.659],\n                       ['2016-02-16', 921.603, 939.398, 937.525, 920.667, 42838640.0, 427507776.0, 93.659],\n                       ['2016-02-15', 904.744, 922.54, 916.92, 903.808, 27849946.0, 271173376.0, 93.659],\n                       ['2016-02-05', 932.842, 933.779, 929.096, 928.159, 27089334.0, 269184384.0, 93.659],\n                       ['2016-02-04', 926.286, 936.589, 931.906, 925.35, 37309948.0, 370586176.0, 93.659],\n                       ['2016-02-03', 922.54, 926.286, 922.54, 915.047, 27457216.0, 269997824.0, 93.659],\n                       ['2016-02-02', 917.857, 939.398, 931.906, 915.984, 36910416.0, 367360512.0, 93.659],\n                       ['2016-02-01', 934.716, 937.525, 917.857, 912.237, 41773216.0, 412635648.0, 93.659],\n                       ['2016-01-29', 912.237, 944.081, 936.589, 907.554, 54443576.0, 540544448.0, 93.659],\n                       ['2016-01-28', 919.73, 926.286, 907.554, 903.808, 30254078.0, 296055328.0, 93.659],\n                       ['2016-01-27', 930.033, 934.716, 925.35, 899.125, 56903704.0, 558510656.0, 93.659],\n                       ['2016-01-26', 966.56, 966.56, 924.413, 923.477, 64790112.0, 653561600.0, 93.659],\n                       ['2016-01-25', 974.052, 977.799, 971.243, 967.496, 37643172.0, 390734880.0, 93.659],\n                       ['2016-01-22', 974.053, 978.736, 974.053, 957.194, 46675216.0, 482984448.0, 93.659],\n                       ['2016-01-21', 981.545, 1006.833, 966.56, 966.56, 60614512.0, 638127872.0, 93.659],\n                       ['2016-01-20', 1002.151, 1011.516, 987.165, 977.799, 60375248.0, 640968960.0, 93.659],\n                       ['2016-01-19', 978.736, 1009.643, 1003.087, 974.989, 50110908.0, 532074688.0, 93.659],\n                       ['2016-01-18', 968.434, 989.039, 974.99, 964.687, 42104088.0, 439917824.0, 93.659],\n                       ['2016-01-15', 998.404, 1011.517, 979.673, 975.926, 44820216.0, 474908128.0, 93.659],\n                       ['2016-01-14', 991.849, 1011.517, 1008.707, 981.546, 66631456.0, 708534976.0, 93.659],\n                       ['2016-01-13', 1019.947, 1024.63, 1003.088, 1002.152, 39170948.0, 424371712.0, 93.659],\n                       ['2016-01-12', 1014.327, 1021.82, 1012.454, 996.532, 56164232.0, 605970816.0, 93.659],\n                       ['2016-01-11', 1030.249, 1037.742, 1007.771, 1000.278, 73201400.0, 800683648.0, 93.659],\n                       ['2016-01-08', 1049.918, 1057.41, 1041.488, 1020.883, 74752760.0, 831334528.0, 93.659],\n                       ['2016-01-07', 1068.65, 1068.65, 1024.63, 1021.82, 17476110.0, 194869488.0, 93.659],\n                       ['2016-01-06', 1069.587, 1082.699, 1079.889, 1066.777, 51570644.0, 591698496.0, 93.659],\n                       ['2016-01-05', 1055.537, 1083.635, 1067.713, 1044.298, 66326996.0, 755531328.0, 93.659],\n                       ['2016-01-04', 1123.909, 1126.718, 1061.157, 1051.791, 56349788.0, 660376128.0, 93.659]]\n        res = easyhistory.Day().get_quarter_history(*test_data)\n        self.assertListEqual(res, normal_data)\n\n    def test_day_data_type_convert(self):\n        test_data = ['2016-02-19', '945.019', '949.701', '940.336', '935.653', '31889824.000', '320939648.000',\n                     '93.659']\n        normal_data = ['2016-02-19', 945.019, 949.701, 940.336, 935.653, 31889824.000, 320939648.000, 93.659]\n        easyhistory.Day().convert_stock_data_type(test_data)\n        self.assertListEqual(test_data, normal_data)\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  }
]