Esempio n. 1
0
    def __init__(self,
                 account,
                 benchmark_code='000300',
                 benchmark_type=MARKET_TYPE.INDEX_CN,
                 if_fq=True):
        """
        if_qf选项是@尧提出的,关于回测的时候成交价格问题(如果按不复权撮合 应该按不复权价格计算assets)
        """
        self.account = account
        self.benchmark_code = benchmark_code  # 默认沪深300
        self.benchmark_type = benchmark_type

        self.fetch = {
            MARKET_TYPE.STOCK_CN: QA_fetch_stock_day_adv,
            MARKET_TYPE.INDEX_CN: QA_fetch_index_day_adv
        }
        self.market_data = QA_fetch_stock_day_adv(self.account.code,
                                                  self.account.start_date,
                                                  self.account.end_date)
        self.if_fq = if_fq

        self._assets = (self.market_value.sum(axis=1) +
                        self.account.daily_cash.set_index('date').cash).fillna(
                            method='pad')

        self.time_gap = QA_util_get_trade_gap(self.account.start_date,
                                              self.account.end_date)
        self.init_cash = self.account.init_cash
        self.init_assets = self.account.init_assets
Esempio n. 2
0
    def test_quotation_base_class_sub_(self):

        qaDAStruct0 = QA_fetch_stock_day_adv('300439', start="2018-01-01", end="2018-01-10")

        qaDAStruct0.show()

        qaDAStruct1 = QA_fetch_stock_day_adv('300439', start="2018-01-01", end="2018-01-05")
        qaDAStruct2 = QA_fetch_stock_day_adv('300439', start="2018-01-06", end="2018-01-10")
        qaDAStruct3 = qaDAStruct1 + qaDAStruct2

        qaDAStruct4 = qaDAStruct3 - qaDAStruct1
        #qaDAStruct5 = qaDAStruct3 - qaDAStruct2

        list1 = []
        for iRow1 in qaDAStruct4:
            list1.append(iRow1)

        list2 = []
        for iRow2 in qaDAStruct2:
            list2.append(iRow2)

        len1 = len(list1)
        len2 = len(list2)
        for iIndex in range(len1):
            aRow = list1[iIndex]
            bRow = list2[iIndex]
            #  循环变量是相等的
            v = aRow.equals(bRow)
            self.assertEqual(v, True)
Esempio n. 3
0
    def __init__(self, account, benchmark_code='000300', benchmark_type=MARKET_TYPE.INDEX_CN, if_fq=True, market_data=None):
        """
        account: QA_Account类/QA_PortfolioView类
        benchmark_code: [str]对照参数代码
        benchmark_type: [QA.PARAM]对照参数的市场
        if_fq: [Bool]原account是否使用复权数据
        if_fq选项是@尧提出的,关于回测的时候成交价格问题(如果按不复权撮合 应该按不复权价格计算assets)
        """
        self.account = account
        self.benchmark_code = benchmark_code  # 默认沪深300
        self.benchmark_type = benchmark_type

        self.fetch = {MARKET_TYPE.STOCK_CN: QA_fetch_stock_day_adv,
                      MARKET_TYPE.INDEX_CN: QA_fetch_index_day_adv}
        if self.account.market_type == MARKET_TYPE.STOCK_CN:
            self.market_data = QA_fetch_stock_day_adv(
                self.account.code, self.account.start_date, self.account.end_date)
        elif self.account.market_type == MARKET_TYPE.FUTURE_CN:
            self.market_data = market_data
        self.if_fq = if_fq

        if self.market_value is not None:
            self._assets = (self.market_value.sum(
                axis=1) + self.account.daily_cash.set_index('date').cash).fillna(method='pad')
        else:
            self._assets = self.account.daily_cash.set_index(
                'date').cash.fillna(method='pad')

        self.time_gap = QA_util_get_trade_gap(
            self.account.start_date, self.account.end_date)
        self.init_cash = self.account.init_cash
        self.init_assets = self.account.init_assets
Esempio n. 4
0
def QA_etl_stock_day(type = "day", mark_day = str(datetime.date.today())):
    if type == "all":
        data = QA_fetch_stock_day_adv(list(QA_fetch_stock_list_adv()['code'])).data.reset_index()
        QA_util_sql_store_mysql(data, "stock_market_day",if_exists='replace')
    elif type == "day":
        data = QA_fetch_stock_day_adv(list(QA_fetch_stock_list_adv()['code']), mark_day)
        if data is None:
            print("We have no MARKET data for the day {}".format(str(datetime.date.today())))
        else:
            data = data.data.reset_index()
            QA_util_sql_store_mysql(data, "stock_market_day",if_exists='append')
Esempio n. 5
0
    def test_quotation_base_class_iter_(self):
        qaDAStruct = QA_fetch_stock_day_adv('300439')

        for iRow in qaDAStruct:
            print(iRow)

        iterObj = qaDAStruct.__iter__()
        a = type(iterObj)
        print(a)
        i = iterObj.__next__()
        print(i)
        i = iterObj.__next__()
        print(i)
        i = iterObj.__next__()
        print(i)
Esempio n. 6
0
    def test_quotation_base_class_iter_(self):
        qaDAStruct = QA_fetch_stock_day_adv('300439')

        for iRow in qaDAStruct:
            print(iRow)

        iterObj = qaDAStruct.__iter__()
        a = type(iterObj)
        print(a)
        i = iterObj.__next__()
        print(i)
        i = iterObj.__next__()
        print(i)
        i = iterObj.__next__()
        print(i)
Esempio n. 7
0
    def __init__(self, account, benchmark_code='000300', benchmark_type=MARKET_TYPE.INDEX_CN):
        self.account = account
        self.benchmark_code = benchmark_code  # 默认沪深300
        self.benchmark_type = benchmark_type

        self.fetch = {MARKET_TYPE.STOCK_CN: QA_fetch_stock_day_adv,
                      MARKET_TYPE.INDEX_CN: QA_fetch_index_day_adv}
        self.market_data = QA_fetch_stock_day_adv(
            self.account.code, self.account.start_date, self.account.end_date)
        self._assets = ((self.market_data.to_qfq().pivot('close') * self.account.daily_hold).sum(
            axis=1) + self.account.daily_cash.set_index('date').cash).fillna(method='pad')

        self.time_gap = QA_util_get_trade_gap(
            self.account.start_date, self.account.end_date)
        self.init_assets = self.account.init_assets
Esempio n. 8
0
 def subscribe_callback(self, code):
     """
     订阅回调
     :param code:
     :return:
     """
     if not isinstance(code, str):
         logger.error('not string , %s' % code)
         return
     today = datetime.datetime(self.cur_year, self.cur_month,
                               self.cur_day).isoformat()[:10]
     end_date = QA_util_get_pre_trade_date(cursor_date=today, n=1)[:10]
     if code not in self.code_list:
         self.code_list.append(code)
         # ETF or Stock, 获取前天的收盘价格
         logger.info("try fetch %s ,%s" % (code, end_date))
         if code.startswith('5') or code.startswith('1'):
             _data = QA_fetch_index_day_adv(code, end_date, end_date)
         else:
             _data = QA_fetch_stock_day_adv(code, end_date, end_date)
         if _data is not None:
             self.pre_market_data = concat(
                 [self.pre_market_data,
                  _data.data.reset_index()])
             logger.info("fetch %s" % _data.data.to_csv(header=False))
Esempio n. 9
0
    def __init__(self, account, benchmark_code='000300', benchmark_type=MARKET_TYPE.INDEX_CN, if_fq=True):
        """
        account: QA_Account类/QA_PortfolioView类
        benchmark_code: [str]对照参数代码
        benchmark_type: [QA.PARAM]对照参数的市场
        if_fq: [Bool]原account是否使用复权数据
        if_fq选项是@尧提出的,关于回测的时候成交价格问题(如果按不复权撮合 应该按不复权价格计算assets)
        """
        self.account = account
        self.benchmark_code = benchmark_code  # 默认沪深300
        self.benchmark_type = benchmark_type

        self.fetch = {MARKET_TYPE.STOCK_CN: QA_fetch_stock_day_adv,
                      MARKET_TYPE.INDEX_CN: QA_fetch_index_day_adv}
        self.market_data = QA_fetch_stock_day_adv(
            self.account.code, self.account.start_date, self.account.end_date)
        self.if_fq = if_fq

        self._assets = (self.market_value.sum(
            axis=1) + self.account.daily_cash.set_index('date').cash).fillna(method='pad')

        self.time_gap = QA_util_get_trade_gap(
            self.account.start_date, self.account.end_date)
        self.init_cash = self.account.init_cash
        self.init_assets = self.account.init_assets
Esempio n. 10
0
    def __QA_backtest_prepare(self):
        """
        这是模型内部的 初始化,主要是初始化一些账户和市场资产
        写成了私有函数
        @yutiansut
        2017/7/20
        """
        if len(str(self.strategy_start_date))==10:
            self.strategy_start_time=str(self.strategy_start_date)+' 15:00:00'
        elif len(str(self.strategy_start_date))==19:
            self.strategy_start_time=str(self.strategy_start_date)
            self.strategy_start_date=str(self.strategy_start_date)[0:10]
        else:
            QA_util_log_info('Wrong start date format')

        if len(str(self.strategy_end_date))==10:
            self.strategy_end_time=str(self.strategy_end_date)+' 15:00:00'
        elif len(str(self.strategy_end_date))==19:
            self.strategy_end_time=str(self.strategy_end_date)
            self.strategy_end_date=str(self.strategy_end_date)[0:10]
        else:
            QA_util_log_info('Wrong end date format')
        # 重新初始账户资产
        self.market = QA_Market(self.commission_fee_coeff)
        self.setting.QA_setting_init()
        self.account.init()
        self.start_real_date = QA_util_get_real_date(
            self.strategy_start_date, self.trade_list, 1)
        self.start_real_time=str(self.start_real_date)+' '+self.strategy_start_time.split(' ')[1]
        self.start_real_id = self.trade_list.index(self.start_real_date)
        self.end_real_date = QA_util_get_real_date(
            self.strategy_end_date, self.trade_list, -1)
        self.end_real_id = self.trade_list.index(self.end_real_date)
        self.end_real_time=str(self.end_real_date)+' '+self.strategy_end_time.split(' ')[1]
        # 重新初始化账户的cookie
        self.account.account_cookie = str(random.random())
        # 初始化股票池的市场数据
        if self.benchmark_type in ['I','index']:
            self.benchmark_data = QA_fetch_index_day_adv(
                self.benchmark_code, self.start_real_date, self.end_real_date)
        elif self.benchmark_type in ['S','stock']:
            self.benchmark_data = QA_fetch_stock_day_adv(
                self.benchmark_code, self.start_real_date, self.end_real_date)
        if self.backtest_type in ['day', 'd', '0x00']:
            self.market_data = QA_fetch_stocklist_day_adv(
                self.strategy_stock_list, self.trade_list[self.start_real_id - int(
                    self.strategy_gap+1)], self.trade_list[self.end_real_id]).to_qfq()

        elif self.backtest_type in ['1min', '5min', '15min', '30min', '60min']:
            self.market_data = QA_fetch_stocklist_min_adv(
                self.strategy_stock_list, QA_util_time_gap(self.start_real_time,self.strategy_gap+1,'<',self.backtest_type),
                QA_util_time_gap(self.end_real_time,1,'>',self.backtest_type), self.backtest_type).to_qfq()

        elif self.backtest_type in ['index_day']:
            self.market_data = QA_fetch_index_day_adv(self.strategy_stock_list, self.trade_list[self.start_real_id - int(
                self.strategy_gap+1)], self.end_real_date)

        elif self.backtest_type in ['index_1min', 'index_5min', 'index_15min', 'index_30min', 'index_60min']:
            self.market_data = QA_fetch_index_min_adv(
                self.strategy_stock_list, QA_util_time_gap(self.start_real_time,self.strategy_gap+1,'<',self.backtest_type.split('_')[1]),  QA_util_time_gap(self.end_real_time,1,'>',self.backtest_type.split('_')[1]), self.backtest_type.split('_')[1])
Esempio n. 11
0
 def test_getAdv_diffQA(self):
     """和QA返回的数据对比一致性
     """
     code = '000001'
     days = 365 * 1.2
     start = (datetime.datetime.now() - datetime.timedelta(days)).date()
     end = (datetime.datetime.now() - datetime.timedelta(0)).date()
     data = TDX.getAdv(code, start, end).data
     self.assertTrue(len(data) > 0, "返回数据数量应该大于0。")
     data2 = QA_fetch_stock_day_adv(code, start, end).data
     if len(data) > len(data2):
         data = data[:len(data2)]
         data = data.reset_index()
         data['date'] = data['date'].astype('datetime64')
         data = data.set_index(['date', 'code'])
         # column顺序重拍
         cols = data2.columns.tolist()
         data = data[cols]
     self.assertTrue(
         len(data) == len(data2),
         "和QA返回的数据,长度不一致 {} {}".format(len(data), len(data2)))
     # 两种方式检测numpy数据一致性
     obo = self.differOneByOne(data, data2)
     # todo index不同
     self.assertTrue(data.equals(data2), "和QA返回的数据不一致{}".format(obo))
Esempio n. 12
0
    def __init__(
        self,
        market_type,
        frequence,
        start,
        end,
        code_list,
        commission_fee,
    ):
        self.user = QA_User()
        self.if_settled = False
        self.account = None
        self.portfolio = None

        self.market = QA_Market()
        self.market_type = market_type
        self.frequence = frequence
        self.broker = QA_BacktestBroker(commission_fee)
        self.broker_name = 'backtest_broker'

        self.start = start
        self.end = end
        self.code_list = code_list

        if self.market_type is MARKET_TYPE.STOCK_CN and self.frequence is FREQUENCE.DAY:
            self.ingest_data = QA_fetch_stock_day_adv(
                self.code_list, self.start, self.end).to_qfq().panel_gen
        elif self.market_type is MARKET_TYPE.STOCK_CN and self.frequence[
                -3:] == 'min':
            self.ingest_data = QA_fetch_stock_min_adv(
                self.code_list, self.start, self.end,
                self.frequence).to_qfq().panel_gen
Esempio n. 13
0
    def __init__(
            self,
            market_type,
            frequence,
            start,
            end,
            code_list,
            commission_fee,
            username='******',
            password='******',
            portfolio_cookie='qatestportfolio'
    ):
        """
        :param market_type: 回测的市场 MARKET_TYPE.STOCK_CN ,
        :param frequence: 'day' '1min' '5min' '15min' '30min' '60min'
        :param start:     开始日期
        :param end:       结束日期
        :param code_list: 股票代码池
        :param commission_fee: 交易佣金
        """
        self.user = QA_User(username=username, password=password)
        self.if_settled = False
        self.account = None
        self.portfolio = self.user.new_portfolio(portfolio_cookie)
        # 🛠todo market_type 应该放在 QA_Market对象里的一个属性
        self.market = QA_Market(if_start_orderthreading=True)
        self.market_type = market_type

        self.frequence = frequence
        self.broker = QA_BacktestBroker(commission_fee)
        self.broker_name = 'backtest_broker'

        self.start = start
        self.end = end
        self.code_list = code_list

        # 🛠todo 检查start日期和结束end日期是否正确
        # 🛠todo 检查code list 是否合法

        # 根据 市场类型,回测周期频率, 和股票代码列表 获取回测数据
        if self.market_type is MARKET_TYPE.STOCK_CN and self.frequence is FREQUENCE.DAY:
            # 获取日线级别的回测数据
            self.ingest_data = QA_fetch_stock_day_adv(
                self.code_list,
                self.start,
                self.end
            ).to_qfq().panel_gen
        elif self.market_type is MARKET_TYPE.STOCK_CN and self.frequence[
                -3:] == 'min':
            # 获取分钟级别的回测数据
            self.ingest_data = QA_fetch_stock_min_adv(
                self.code_list,
                self.start,
                self.end,
                self.frequence
            ).to_qfq().panel_gen

        else:
            QA_util_log_info("{} 的市场类型没有实现!".format(market_type))
Esempio n. 14
0
    def __init__(self,
                 account,
                 benchmark_code='000300',
                 benchmark_type=MARKET_TYPE.INDEX_CN,
                 if_fq=True,
                 market_data=None,
                 auto_reload=False):
        """
        account: QA_Account类/QA_PortfolioView类
        benchmark_code: [str]对照参数代码
        benchmark_type: [QA.PARAM]对照参数的市场
        if_fq: [Bool]原account是否使用复权数据
        if_fq选项是@尧提出的,关于回测的时候成交价格问题(如果按不复权撮合 应该按不复权价格计算assets)
        """
        self.account = account
        self.benchmark_code = benchmark_code  # 默认沪深300
        self.benchmark_type = benchmark_type
        self.client = DATABASE.risk

        self.client.create_index([("account_cookie", ASCENDING),
                                  ("user_cookie", ASCENDING),
                                  ("portfolio_cookie", ASCENDING)],
                                 unique=True)
        if auto_reload:
            pass
        else:
            self.fetch = {
                MARKET_TYPE.STOCK_CN: QA_fetch_stock_day_adv,
                MARKET_TYPE.INDEX_CN: QA_fetch_index_day_adv
            }
            if market_data == None:
                if self.account.market_type == MARKET_TYPE.STOCK_CN:
                    self.market_data = QA_fetch_stock_day_adv(
                        self.account.code, self.account.start_date,
                        self.account.end_date)
                elif self.account.market_type == MARKET_TYPE.FUTURE_CN:
                    self.market_data = QA_fetch_future_day_adv(
                        self.account.code, self.account.start_date,
                        self.account.end_date)
            else:
                self.market_data = market_data
            self.if_fq = if_fq
            if self.account.market_type == MARKET_TYPE.FUTURE_CN:
                self.if_fq = False  # 如果是期货, 默认设为FALSE

            if self.market_value is not None:
                self._assets = (
                    self.market_value.sum(axis=1) +
                    self.account.daily_cash.set_index('date').cash).fillna(
                        method='pad')
            else:
                self._assets = self.account.daily_cash.set_index(
                    'date').cash.fillna(method='pad')

            self.time_gap = QA_util_get_trade_gap(self.account.start_date,
                                                  self.account.end_date)
            self.init_cash = self.account.init_cash
            self.init_assets = self.account.init_assets
Esempio n. 15
0
    def test_GetItem(self):
        print("ok get item")
        qaDAStruct0 = QA_fetch_stock_day_adv('300439', start="2018-01-01", end="2018-01-10")

        #for iRow int qaDAStruct0.index:

        closePrices = qaDAStruct0.__getitem__('close')

        print(closePrices)


    # 🛠todo  测试  __getattr__
    # 🛠todo  测试  ix
    # 🛠todo  测试  iloc
    # 🛠todo  测试  loc
    # 🛠todo  测试  iloc#
    # 🛠todo  测试  iloc#
    # 🛠todo  测试  iloc
Esempio n. 16
0
def ETL_stock_day(codes, start=None, end=None):
    if start is None:
        start = '2008-01-01'

    if end is None:
        end = QA_util_today_str()

    if start != end:
        rng = pd.Series(pd.date_range(start, end, freq='D')).apply(lambda x: str(x)[0:10])
    else:
        rng = str(start)[0:10]

    start_date = QA_util_get_pre_trade_date(start,100)
    data = QA_fetch_stock_day_adv(codes,start_date,end)
    res1 = data.to_qfq().data
    res1.columns = [x + '_qfq' for x in res1.columns]
    data = data.data.join(res1).fillna(0).reset_index()
    res = data.groupby('code').apply(pct)
    res = res.reset_index(level = 0,drop = True).reset_index().set_index(['date','code']).loc[rng].replace([np.inf, -np.inf], 0)
    res = res.where((pd.notnull(res)), None)
    return(res)
Esempio n. 17
0
    def get_data(self, code, start, end, if_fq):

        if if_fq:
            data = QA_util_to_json_from_pandas(
                QA_fetch_stock_day_adv(code, start, end).to_qfq().data)

            self.write({'result': data})
        else:
            data = QA_util_to_json_from_pandas(
                QA_fetch_stock_day(code, start, end, format='pd'))

            self.write({'result': data})
Esempio n. 18
0
    def test_quotation_base_class_sub_(self):

        qaDAStruct0 = QA_fetch_stock_day_adv('300439', start="2018-01-01", end="2018-01-10")

        qaDAStruct0.show()

        qaDAStruct1 = QA_fetch_stock_day_adv('300439', start="2018-01-01", end="2018-01-05")
        qaDAStruct2 = QA_fetch_stock_day_adv('300439', start="2018-01-06", end="2018-01-10")
        qaDAStruct3 = qaDAStruct1 + qaDAStruct2

        qaDAStruct4 = qaDAStruct3 - qaDAStruct1
        #qaDAStruct5 = qaDAStruct3 - qaDAStruct2

        list1 = []
        for iRow1 in qaDAStruct4:
            list1.append(iRow1)

        list2 = []
        for iRow2 in qaDAStruct2:
            list2.append(iRow2)

        len1 = len(list1)
        len2 = len(list2)
        for iIndex in range(len1):
            aRow = list1[iIndex]
            bRow = list2[iIndex]
            # ✅ 循环变量是相等的
            v = aRow.equals(bRow)
            self.assertEqual(v, True)
Esempio n. 19
0
 def do0_ReverseAttributes_test(self):
     qaDAStruct = QA_fetch_stock_day_adv('300439', start="2018-01-01", end="2018-01-10")
     rev_qaDAStruct = reversed(qaDAStruct)
     list1 = []
     for iRow in qaDAStruct:
         print(iRow)
         list1.append(iRow)
     print('--------------')
     list2 = []
     for iRowRev in rev_qaDAStruct:
         print(iRowRev)
         list2.append(iRowRev)
     print('--------------')
Esempio n. 20
0
    def test_quotation_base_class_add_(self):
        qaDAStruct0 = QA_fetch_stock_day_adv('300439', start="2018-01-01", end="2018-01-10")

        qaDAStruct0.show()

        qaDAStruct1 = QA_fetch_stock_day_adv('300439', start="2018-01-01", end="2018-01-05")
        qaDAStruct2 = QA_fetch_stock_day_adv('300439', start="2018-01-06", end="2018-01-10")
        qaDAStruct3 = qaDAStruct1 + qaDAStruct2

        qaDAStruct3.show()

        # 🛠todo 进一步研究为何不相等
        b = qaDAStruct0().equals(qaDAStruct3())
        #self.assertEqual(b, True)

        # 🛠todo 进一步研究为何不相等
        # 为何这个就不写 , 是不是 比较 __eq__的问题
        # self.assertEqual( qaDAStruct0 , qaDAStruct3)


        list1 = []
        for iRow1 in qaDAStruct0:
            list1.append(iRow1)

        list2 = []
        for iRow2 in qaDAStruct0:
            list2.append(iRow2)

        len1 = len(list1)
        len2 = len(list2)

        for iIndex in range(len1):
            aRow = list1[iIndex]
            bRow = list2[iIndex]

            # 循环变量是相等的
            v = aRow.equals(bRow)
            self.assertEqual(v, True)
Esempio n. 21
0
 def test_getAdv_diffQA(self):
     """和QA返回的数据对比一致性
     """
     code = '000001'
     days = 365 * 1.2
     start = datetime.datetime.now() - datetime.timedelta(days)
     end = datetime.datetime.now() - datetime.timedelta(0)
     df = qm.getAdv(code, start, end)
     self.assertTrue(len(df) > 0, "返回数据数量应该大于0。")
     df2 = QA_fetch_stock_day_adv(code, start, end)
     self.assertTrue(len(df) == len(df2), "和QA返回的数据,长度不一致")
     # 两种方式检测numpy数据一致性
     obo = self.differOneByOne(df.data, df2.data)
     self.assertTrue(np.array_equal(df, df2), "和QA返回的数据不一致{}".format(obo))
Esempio n. 22
0
 def test_quotation_base_class_reverse_(self):
     qaDAStruct = QA_fetch_stock_day_adv('300439',start="2018-01-01", end="2018-01-10")
     rev_qaDAStruct = reversed(qaDAStruct)
     list1 = []
     for iRow in qaDAStruct:
         print(iRow)
         list1.append(iRow)
     print('--------------')
     list2 = []
     for iRowRev in rev_qaDAStruct:
         print(iRowRev)
         list2.append(iRowRev)
     print('--------------')
     #没有 reverse
     pass
Esempio n. 23
0
    def __init__(
        self,
        market_type,
        frequence,
        start,
        end,
        code_list,
        commission_fee,
    ):
        """

        :param market_type: 回测的市场 MARKET_TYPE.STOCK_CN ,
        :param frequence: 'day' '1min' '5min' '15min' '30min' '60min'
        :param start:     开始日期
        :param end:       结束日期
        :param code_list: 股票代码池
        :param commission_fee: 交易佣金
        """
        self.user = QA_User()
        self.if_settled = False
        self.account = None
        self.portfolio = None

        self.market = QA_Market()
        self.market_type = market_type
        self.frequence = frequence
        self.broker = QA_BacktestBroker(commission_fee)
        self.broker_name = 'backtest_broker'

        self.start = start
        self.end = end
        self.code_list = code_list

        if self.market_type is MARKET_TYPE.STOCK_CN and self.frequence is FREQUENCE.DAY:
            self.ingest_data = QA_fetch_stock_day_adv(
                self.code_list, self.start, self.end).to_qfq().panel_gen
        elif self.market_type is MARKET_TYPE.STOCK_CN and self.frequence[
                -3:] == 'min':
            self.ingest_data = QA_fetch_stock_min_adv(
                self.code_list, self.start, self.end,
                self.frequence).to_qfq().panel_gen
        else:
            QA_util_log_info("{} 的市场类型没有实现!".format(market_type))
Esempio n. 24
0
    def get(self):
        """
        采用了get_arguents来获取参数
        默认参数: code-->000001 start-->2017-01-01 end-->today

        """
        code = self.get_argument('code', default='000001')
        start = self.get_argument('start', default='2017-01-01')
        end = self.get_argument('end', default=str(datetime.date.today()))
        if_fq = self.get_argument('if_fq', default=False)
        if if_fq:
            data = QA_util_to_json_from_pandas(
                QA_fetch_stock_day_adv(code, start, end).to_qfq().data)

            self.write({'result': data})
        else:
            data = QA_util_to_json_from_pandas(
                QA_fetch_stock_day(code, start, end, format='pd'))

            self.write({'result': data})
Esempio n. 25
0
    def test_quotation_base_class_add_(self):
        qaDAStruct0 = QA_fetch_stock_day_adv('300439', start="2018-01-01", end="2018-01-10")

        qaDAStruct0.show()

        qaDAStruct1 = QA_fetch_stock_day_adv('300439', start="2018-01-01", end="2018-01-05")
        qaDAStruct2 = QA_fetch_stock_day_adv('300439', start="2018-01-06", end="2018-01-10")
        qaDAStruct3 = qaDAStruct1 + qaDAStruct2

        qaDAStruct3.show()

        # 🛠todo 进一步研究为何不相等
        b = qaDAStruct0().equals(qaDAStruct3())
        #self.assertEqual(b, True)

        # 🛠todo 进一步研究为何不相等
        # 为何这个就不写 , 是不是 比较 __eq__的问题
        # self.assertEqual( qaDAStruct0 , qaDAStruct3)


        list1 = []
        for iRow1 in qaDAStruct0:
            list1.append(iRow1)

        list2 = []
        for iRow2 in qaDAStruct0:
            list2.append(iRow2)

        len1 = len(list1)
        len2 = len(list2)

        for iIndex in range(len1):
            aRow = list1[iIndex]
            bRow = list2[iIndex]

            #✅ 循环变量是相等的
            v = aRow.equals(bRow)
            self.assertEqual(v, True)
Esempio n. 26
0
class QA_Risk():
    """QARISK 是一个风险插件

    需要加载一个account/portfolio类进来:
    需要有
    code,start_date,end_date,daily_cash,daily_hold
    """

    def __init__(self, account, benchmark_code='000300', benchmark_type=MARKET_TYPE.INDEX_CN):
        self.account = account
        self.benchmark_code = benchmark_code  # 默认沪深300
        self.benchmark_type = benchmark_type

        self.fetch = {MARKET_TYPE.STOCK_CN: QA_fetch_stock_day_adv,
                      MARKET_TYPE.INDEX_CN: QA_fetch_index_day_adv}
        self.market_data = QA_fetch_stock_day_adv(
            self.account.code, self.account.start_date, self.account.end_date)
        self._assets = ((self.market_data.to_qfq().pivot('close') * self.account.daily_hold).sum(
            axis=1) + self.account.daily_cash.set_index('date').cash).fillna(method='pad')

        self.time_gap = QA_util_get_trade_gap(
            self.account.start_date, self.account.end_date)
        self.init_assets = self.account.init_assets

    def __repr__(self):
        return '< QA_RISK ANALYSIS ACCOUNT/PORTFOLIO >'

    def __call__(self):
        return pd.DataFrame([self.message])

    @property
    def assets(self):
        x1 = self._assets.reset_index()
        return x1.assign(date=pd.to_datetime(x1.date)).set_index('date')[0]

    @property
    def max_dropback(self):
        """最大回撤
        """
        return round(float(max([(self.assets.iloc[idx] - self.assets.iloc[idx::].min())/self.assets.iloc[idx] for idx in range(len(self.assets))])),2)

    @property
    def profit(self):
        return round(float(self.calc_profit(self.assets)),2)

    @property
    def profit_pct(self):
        """利润
        """
        return self.calc_profitpctchange(self.assets)

    @property
    def annualize_return(self):
        """年化收益

        Returns:
            [type] -- [description]
        """

        return round(float(self.calc_annualize_return(self.assets, self.time_gap)),2)

    @property
    def volatility(self):
        """波动率

        Returns:
            [type] -- [description]
        """
        return round(float(self.profit_pct.std() * math.sqrt(250)),2)

    
    @property
    @lru_cache()
    def message(self):
        return {
            'account_cookie': self.account.account_cookie,
            'portfolio_cookie': self.account.portfolio_cookie,
            'user_cookie': self.account.user_cookie,
            'annualize_return': self.annualize_return,
            'profit': self.profit,
            'max_dropback': self.max_dropback,
            'time_gap': self.time_gap,
            'volatility': self.volatility,
            'benchmark_code': self.benchmark_code,
            'bm_annualizereturn':self.benchmark_annualize_return,
            'beta': self.beta,
            'alpha': self.alpha,
            'sharpe': self.sharpe,
            'init_assets': round(float(self.init_assets),2),
            'last_assets': round(float(self.assets.iloc[-1]),2)
        }

    @property
    def benchmark_data(self):
        """
        基准组合的行情数据(一般是组合,可以调整)
        """
        return self.fetch[self.benchmark_type](
            self.benchmark_code, self.account.start_date, self.account.end_date)

    @property
    def benchmark_assets(self):
        """
        基准组合的账户资产队列
        """
        return (self.benchmark_data.open / float(self.benchmark_data.open.iloc[0]) * float(self.init_assets))

    @property
    def benchmark_annualize_return(self):
        """基准组合的年化收益

        Returns:
            [type] -- [description]
        """

        return round(float(self.calc_annualize_return(self.benchmark_assets, self.time_gap)),2)

    @property
    def benchmark_profitpct(self):
        """
        benchmark 基准组合的收益百分比计算
        """
        return self.calc_profitpctchange(self.benchmark_assets)

    @property
    def beta(self):
        """
        beta比率 组合的系统性风险
        """
        return round(float(self.calc_beta(self.profit_pct.dropna(), self.benchmark_profitpct.dropna())),2)

    @property
    def alpha(self):
        """
        alpha比率 与市场基准收益无关的超额收益率
        """
        return round(float(self.calc_alpha(self.annualize_return, self.benchmark_annualize_return, self.beta, 0.05)),2)

    @property
    def sharpe(self):
        """
        夏普比率

        """
        return round(float(self.calc_sharpe(self.annualize_return, self.volatility, 0.05)),2)

    @property
    def sortino(self):
        """ 
        索提诺比率 投资组合收益和下行风险比值

        """
        pass

    @property
    def calmar(self):
        """
        卡玛比率
        """
        pass

    def set_benchmark(self, code, market_type):
        self.benchmark_code = code
        self.benchmark_type = market_type

    def calc_annualize_return(self, assets, days):
        return (float(assets.iloc[-1]) / float(assets.iloc[0]) - 1)/(float(days) / 250)

    def calc_profitpctchange(self, assets):
        return self.assets[::-1].pct_change()

    def calc_beta(self, assest_profit, benchmark_profit):

        calc_cov = np.cov(assest_profit, benchmark_profit)
        beta = calc_cov[0, 1] / calc_cov[1, 1]
        return beta

    def calc_alpha(self, annualized_returns, benchmark_annualized_returns, beta, r=0.05):

        alpha = (annualized_returns - r) - (beta) * \
            (benchmark_annualized_returns - r)
        return alpha

    def calc_profit(self, assets):
        """
        计算账户收益
        期末资产/期初资产 -1
        """
        return (float(assets.iloc[-1]) / float(assets.iloc[0])) - 1

    def calc_sharpe(self, annualized_returns, volatility_year, r=0.05):
        """
        计算夏普比率
        r是无风险收益
        """
        return (annualized_returns - r) / volatility_year

    def save(self):
        """save to mongodb

        """
        save_riskanalysis(self.message)

    def plot_assets_curve(self, length=14, height=12):
        """
        资金曲线叠加图
        """
        plt.figure(figsize=(length, 1.5))
        plt.subplot(211)
        plt.title('BASIC INFO',fontsize=12)
        plt.axis([0, length, 0, 0.6])
        plt.axis('off')
        i=0
        for item in ['account_cookie','portfolio_cookie','user_cookie']:
            plt.text(i, 0.5, '{} : {}'.format(item,self.message[item]), fontsize=10, rotation=0, wrap=True)
            i+=(length/2.8)
        i=0
        for item in ['benchmark_code','time_gap','max_dropback']:
            plt.text(i, 0.4, '{} : {}'.format(item,self.message[item]),fontsize=10, ha='left', rotation=0, wrap=True)
            i+=(length/2.8)
        i=0
        for item in ['annualize_return','bm_annualizereturn','profit']:
            plt.text(i, 0.3, '{} : {} %'.format(item,self.message.get(item,0)),fontsize=10, ha='left', rotation=0, wrap=True)
            i+=length/2.8
        i=0
        for item in ['init_assets','last_assets','volatility']:
            plt.text(i, 0.2, '{} : {} '.format(item,self.message[item]),fontsize=10, ha='left', rotation=0, wrap=True)
            i+=length/2.8
        i=0
        for item in ['alpha','beta','sharpe']:
            plt.text(i, 0.1, '{} : {}'.format(item,self.message[item]), ha='left', fontsize=10,rotation=0, wrap=True)
            i+=length/2.8
        #plt.figure(figsize=(length, height))
        plt.subplot(212)
        plt.style.use('ggplot')
        self.assets.plot()
        self.benchmark_assets.xs(self.benchmark_code, level=1).plot()

        asset_p = mpatches.Patch(
            color='red', label='{}'.format(self.account.account_cookie))
        asset_b = mpatches.Patch(
            label='benchmark {}'.format(self.benchmark_code))
        plt.legend(handles=[asset_p, asset_b], loc=1)
        plt.title('ASSET AND BENCKMARK')
        plt.show()
Esempio n. 27
0
class QA_Risk():
    """QARISK 是一个风险插件

    需要加载一个account/portfolio类进来:
    需要有
    code,start_date,end_date,daily_cash,daily_hold

    TODO:
    资金利用率 反应资金的利用程度
    股票周转率 反应股票的持仓天数
    预期PNL/统计学PNL
    """
    def __init__(self,
                 account,
                 benchmark_code='000300',
                 benchmark_type=MARKET_TYPE.INDEX_CN,
                 if_fq=True,
                 market_data=None):
        """
        account: QA_Account类/QA_PortfolioView类
        benchmark_code: [str]对照参数代码
        benchmark_type: [QA.PARAM]对照参数的市场
        if_fq: [Bool]原account是否使用复权数据
        if_fq选项是@尧提出的,关于回测的时候成交价格问题(如果按不复权撮合 应该按不复权价格计算assets)
        """
        self.account = account
        self.benchmark_code = benchmark_code  # 默认沪深300
        self.benchmark_type = benchmark_type

        self.fetch = {
            MARKET_TYPE.STOCK_CN: QA_fetch_stock_day_adv,
            MARKET_TYPE.INDEX_CN: QA_fetch_index_day_adv
        }
        if self.account.market_type == MARKET_TYPE.STOCK_CN:
            self.market_data = QA_fetch_stock_day_adv(self.account.code,
                                                      self.account.start_date,
                                                      self.account.end_date)
        elif self.account.market_type == MARKET_TYPE.FUTURE_CN:
            self.market_data = market_data
        self.if_fq = if_fq

        self._assets = (self.market_value.sum(axis=1) +
                        self.account.daily_cash.set_index('date').cash).fillna(
                            method='pad')

        self.time_gap = QA_util_get_trade_gap(self.account.start_date,
                                              self.account.end_date)
        self.init_cash = self.account.init_cash
        self.init_assets = self.account.init_assets

    def __repr__(self):
        return '< QA_RISK ANALYSIS ACCOUNT/PORTFOLIO >'

    def __call__(self):
        return pd.DataFrame([self.message])

    @property
    @lru_cache()
    def market_value(self):
        """每日每个股票持仓市值表

        Returns:
            pd.DataFrame -- 市值表
        """

        if self.if_fq:
            return self.market_data.to_qfq().pivot('close').fillna(
                method='ffill') * self.account.daily_hold
        else:
            return self.market_data.pivot('close').fillna(
                method='ffill') * self.account.daily_hold

    @property
    @lru_cache()
    def daily_market_value(self):
        """每日持仓总市值表

        Returns:
            pd.DataFrame -- 市值表
        """

        return self.market_value.sum(axis=1)

    @property
    def assets(self):
        x1 = self._assets.reset_index()
        return x1.assign(date=pd.to_datetime(x1.date)).set_index('date')[0]

    @property
    def max_dropback(self):
        """最大回撤
        """
        return round(
            float(
                max([(self.assets.iloc[idx] - self.assets.iloc[idx::].min()) /
                     self.assets.iloc[idx]
                     for idx in range(len(self.assets))])), 2)

    @property
    def total_commission(self):
        """总手续费
        """
        return -abs(round(self.account.history_table.commission.sum(), 2))

    @property
    def total_tax(self):
        """总印花税

        """

        return -abs(round(self.account.history_table.tax.sum(), 2))

    @property
    def profit_construct(self):
        """利润构成

        Returns:
            dict -- 利润构成表
        """

        return {
            'total_buyandsell':
            round(self.profit_money - self.total_commission - self.total_tax,
                  2),
            'total_tax':
            self.total_tax,
            'total_commission':
            self.total_commission,
            'total_profit':
            self.profit_money
        }

    @property
    def profit_money(self):
        """盈利额

        Returns:
            [type] -- [description]
        """

        return round(self.assets.iloc[-1] - self.init_cash, 2)

    @property
    def profit(self):
        """盈利率(百分比)

        Returns:
            [type] -- [description]
        """

        return round(float(self.calc_profit(self.assets)), 2)

    @property
    def profit_pct(self):
        """利润
        """
        return self.calc_profitpctchange(self.assets)

    @property
    def annualize_return(self):
        """年化收益

        Returns:
            [type] -- [description]
        """

        return round(
            float(self.calc_annualize_return(self.assets, self.time_gap)), 2)

    @property
    def volatility(self):
        """波动率

        Returns:
            [type] -- [description]
        """
        return round(float(self.profit_pct.std() * math.sqrt(250)), 2)

    @property
    @lru_cache()
    def message(self):
        return {
            'account_cookie': self.account.account_cookie,
            'portfolio_cookie': self.account.portfolio_cookie,
            'user_cookie': self.account.user_cookie,
            'annualize_return': round(self.annualize_return, 2),
            'profit': round(self.profit, 2),
            'max_dropback': self.max_dropback,
            'time_gap': self.time_gap,
            'volatility': self.volatility,
            'benchmark_code': self.benchmark_code,
            'bm_annualizereturn': self.benchmark_annualize_return,
            'bn_profit': self.benchmark_profit,
            'beta': self.beta,
            'alpha': self.alpha,
            'sharpe': self.sharpe,
            'init_cash': "%0.2f" % (float(self.init_cash)),
            'last_assets': "%0.2f" % (float(self.assets.iloc[-1])),
            'total_tax': self.total_tax,
            'total_commission': self.total_commission,
            'profit_money': self.profit_money

            # 'init_assets': round(float(self.init_assets), 2),
            # 'last_assets': round(float(self.assets.iloc[-1]), 2)
        }

    @property
    def benchmark_data(self):
        """
        基准组合的行情数据(一般是组合,可以调整)
        """
        return self.fetch[self.benchmark_type](self.benchmark_code,
                                               self.account.start_date,
                                               self.account.end_date)

    @property
    def benchmark_assets(self):
        """
        基准组合的账户资产队列
        """
        return (self.benchmark_data.close /
                float(self.benchmark_data.open.iloc[0]) *
                float(self.init_cash))

    @property
    def benchmark_profit(self):
        """
        基准组合的收益
        """
        return round(float(self.calc_profit(self.benchmark_assets)), 2)

    @property
    def benchmark_annualize_return(self):
        """基准组合的年化收益

        Returns:
            [type] -- [description]
        """

        return round(
            float(
                self.calc_annualize_return(self.benchmark_assets,
                                           self.time_gap)), 2)

    @property
    def benchmark_profitpct(self):
        """
        benchmark 基准组合的收益百分比计算
        """
        return self.calc_profitpctchange(self.benchmark_assets)

    @property
    def beta(self):
        """
        beta比率 组合的系统性风险
        """
        return round(
            float(
                self.calc_beta(self.profit_pct.dropna(),
                               self.benchmark_profitpct.dropna())), 2)

    @property
    def alpha(self):
        """
        alpha比率 与市场基准收益无关的超额收益率
        """
        return round(
            float(
                self.calc_alpha(self.annualize_return,
                                self.benchmark_annualize_return, self.beta,
                                0.05)), 2)

    @property
    def sharpe(self):
        """
        夏普比率

        """
        return round(
            float(
                self.calc_sharpe(self.annualize_return, self.volatility,
                                 0.05)), 2)

    @property
    def sortino(self):
        """ 
        索提诺比率 投资组合收益和下行风险比值

        """
        pass

    @property
    def calmar(self):
        """
        卡玛比率
        """
        pass

    def set_benchmark(self, code, market_type):
        self.benchmark_code = code
        self.benchmark_type = market_type

    def calc_annualize_return(self, assets, days):
        return round((float(assets.iloc[-1]) / float(assets.iloc[0]) - 1) /
                     (float(days) / 250), 2)

    def calc_profitpctchange(self, assets):
        return self.assets[::-1].pct_change()

    def calc_beta(self, assest_profit, benchmark_profit):

        calc_cov = np.cov(assest_profit, benchmark_profit)
        beta = calc_cov[0, 1] / calc_cov[1, 1]
        return beta

    def calc_alpha(self,
                   annualized_returns,
                   benchmark_annualized_returns,
                   beta,
                   r=0.05):

        alpha = (annualized_returns - r) - (beta) * \
            (benchmark_annualized_returns - r)
        return alpha

    def calc_profit(self, assets):
        """
        计算账户收益
        期末资产/期初资产 -1
        """
        return (float(assets.iloc[-1]) / float(self.init_cash)) - 1

    def calc_sharpe(self, annualized_returns, volatility_year, r=0.05):
        """
        计算夏普比率
        r是无风险收益
        """
        # 会出现0
        if volatility_year == 0:
            return 0
        return (annualized_returns - r) / volatility_year

    @property
    def max_holdmarketvalue(self):
        """最大持仓市值

        Returns:
            [type] -- [description]
        """

        return self.daily_market_value.max()

    @property
    def min_holdmarketvalue(self):
        """最小持仓市值

        Returns:
            [type] -- [description]
        """

        return self.daily_market_value.min()

    @property
    def average_holdmarketvalue(self):
        """平均持仓市值

        Returns:
            [type] -- [description]
        """

        return self.daily_market_value.mean()

    @property
    def max_cashhold(self):
        """最大闲置资金
        """

        return self.account.daily_cash.cash.max()

    @property
    def min_cashhold(self):
        """最小闲置资金
        """

        return self.account.daily_cash.cash.min()

    @property
    def average_cashhold(self):
        """平均闲置资金

        Returns:
            [type] -- [description]
        """

        return self.account.daily_cash.cash.mean()

    def save(self):
        """save to mongodb

        """
        save_riskanalysis(self.message)

    def plot_assets_curve(self, length=14, height=12):
        """
        资金曲线叠加图
        @Roy T.Burns 2018/05/29 修改百分比显示错误
        """
        plt.style.use('ggplot')
        plt.figure(figsize=(length, height))
        plt.subplot(211)
        plt.title('BASIC INFO', fontsize=12)
        plt.axis([0, length, 0, 0.6])
        plt.axis('off')
        i = 0
        for item in ['account_cookie', 'portfolio_cookie', 'user_cookie']:
            plt.text(i,
                     0.5,
                     '{} : {}'.format(item, self.message[item]),
                     fontsize=10,
                     rotation=0,
                     wrap=True)
            i += (length / 2.8)
        i = 0
        for item in ['benchmark_code', 'time_gap', 'max_dropback']:
            plt.text(i,
                     0.4,
                     '{} : {}'.format(item, self.message[item]),
                     fontsize=10,
                     ha='left',
                     rotation=0,
                     wrap=True)
            i += (length / 2.8)
        i = 0
        for item in ['annualize_return', 'bm_annualizereturn', 'profit']:
            plt.text(i,
                     0.3,
                     '{} : {} %'.format(item,
                                        self.message.get(item, 0) * 100),
                     fontsize=10,
                     ha='left',
                     rotation=0,
                     wrap=True)
            i += length / 2.8
        i = 0
        for item in ['init_cash', 'last_assets', 'volatility']:
            plt.text(i,
                     0.2,
                     '{} : {} '.format(item, self.message[item]),
                     fontsize=10,
                     ha='left',
                     rotation=0,
                     wrap=True)
            i += length / 2.8
        i = 0
        for item in ['alpha', 'beta', 'sharpe']:
            plt.text(i,
                     0.1,
                     '{} : {}'.format(item, self.message[item]),
                     ha='left',
                     fontsize=10,
                     rotation=0,
                     wrap=True)
            i += length / 2.8
        plt.subplot(212)
        self.assets.plot()
        self.benchmark_assets.xs(self.benchmark_code, level=1).plot()

        asset_p = mpatches.Patch(color='red',
                                 label='{}'.format(
                                     self.account.account_cookie))
        asset_b = mpatches.Patch(
            label='benchmark {}'.format(self.benchmark_code))
        plt.legend(handles=[asset_p, asset_b], loc=1)
        plt.title('ASSET AND BENCKMARK')

        return plt

    def plot_dailyhold(self, start=None, end=None):
        """
        使用热力图画出每日持仓
        """
        start = self.account.start_date if start is None else start
        end = self.account.end_date if end is None else end
        _, ax = plt.subplots(figsize=(20, 8))
        sns.heatmap(self.account.daily_hold.reset_index().drop(
            'account_cookie', axis=1).set_index('date').loc[start:end],
                    cmap="YlGnBu",
                    linewidths=0.05,
                    ax=ax)
        ax.set_title('HOLD TABLE --ACCOUNT: {}'.format(
            self.account.account_cookie))
        ax.set_xlabel('Code')
        ax.set_ylabel('DATETIME')

        return plt

    def plot_signal(self, start=None, end=None):
        """
        使用热力图画出买卖信号
        """
        start = self.account.start_date if start is None else start
        end = self.account.end_date if end is None else end
        _, ax = plt.subplots(figsize=(20, 18))
        sns.heatmap(self.account.trade.reset_index().drop(
            'account_cookie', axis=1).set_index('datetime').loc[start:end],
                    cmap="YlGnBu",
                    linewidths=0.05,
                    ax=ax)
        ax.set_title('SIGNAL TABLE --ACCOUNT: {}'.format(
            self.account.account_cookie))
        ax.set_xlabel('Code')
        ax.set_ylabel('DATETIME')
        return plt

    def generate_plots(self):
        """
        生成图像
        """
        self.plot_assets_curve()
        self.plot_dailyhold()
        self.plot_signal()
Esempio n. 28
0
 def get_trade_marketdata(self, rx,gap=3):
     data=QA_fetch_stock_day_adv(rx.code.values[0], QA_util_date_gap(rx.date.values[0], gap, methods='lt'), QA_util_date_gap(rx.sell_date.values[0][-1], gap, methods='gt'))
     data['tradesignal']='N'
     return data
Esempio n. 29
0
def predict(trading_date,
            strategy_id='机器学习1号',
            account1='name:client-1',
            working_dir=working_dir,
            ui_log=None,
            exceptions=exceptions):

    try:
        QA_util_log_info(
            '##JOB01 Now Got Account Info ==== {}'.format(str(trading_date)),
            ui_log)
        client = get_Client()
        account1 = account1
        account_info = client.get_account(account1)
        print(account_info)
        sub_accounts = client.get_positions(account1)['sub_accounts']
        try:
            frozen = float(
                client.get_positions(account1)['positions'].set_index(
                    '证券代码').loc[exceptions]['市值'].sum())
        except:
            frozen = 0
        sub_accounts = sub_accounts - frozen
    except:
        send_email('错误报告', '云服务器错误,请检查', trading_date)
        send_actionnotice(strategy_id,
                          '错误报告:{}'.format(trading_date),
                          '云服务器错误,请检查',
                          direction='HOLD',
                          offset='HOLD',
                          volume=None)
    try:
        QA_util_log_info(
            '##JOB02 Now Load Model ==== {}'.format(str(trading_date)), ui_log)
        stock_model_temp, stock_info_temp = Stock.load_model(
            'stock', working_dir=working_dir)
        index_model_temp, index_info_temp = Index.load_model(
            'index', working_dir=working_dir)
        safe_model_temp, safe_info_temp = Index.load_model(
            'safe', working_dir=working_dir)
    except:
        send_email('错误报告', '无法正确加载模型,请检查', trading_date)
        send_actionnotice(strategy_id,
                          '错误报告:{}'.format(trading_date),
                          '无法正确加载模型,请检查',
                          direction='HOLD',
                          offset='HOLD',
                          volume=None)

    QA_util_log_info(
        '##JOB03 Now Model Predict ==== {}'.format(str(trading_date)), ui_log)
    #index_list,index_report,index_top_report = Index.check_model(index_model_temp, QA_util_get_last_day(trading_date),QA_util_get_last_day(trading_date),index_info_temp['cols'], 'INDEXT_TARGET5', 0.3)
    index_tar, index_b = Index.model_predict(index_model_temp,
                                             str(trading_date[0:7]) + "-01",
                                             trading_date,
                                             index_info_temp['cols'])

    #safe_list,safe_report,safe_top_report = Index.check_model(safe_model_temp, QA_util_get_last_day(trading_date),QA_util_get_last_day(trading_date),safe_info_temp['cols'], 'INDEXT_TARGET', 0.3)
    safe_tar, safe_b = Index.model_predict(safe_model_temp,
                                           str(trading_date[0:7]) + "-01",
                                           trading_date,
                                           index_info_temp['cols'])

    stock_list, report, top_report = Stock.check_model(
        stock_model_temp, QA_util_get_last_day(trading_date),
        QA_util_get_last_day(trading_date), stock_info_temp['cols'], 0.42)
    stock_tar, stock_b = Stock.model_predict(stock_model_temp,
                                             str(trading_date[0:7]) + "-01",
                                             trading_date,
                                             stock_info_temp['cols'])

    tar = combine_model(index_b, stock_b, safe_b,
                        str(trading_date[0:7]) + "-01", trading_date)
    QA_util_log_info(
        '##JOB03 Now Concat Result ==== {}'.format(str(trading_date)), ui_log)
    try:
        tar1 = tar.loc[trading_date]
    except:
        tar1 = None

    QA_util_log_info(
        '##JOB04 Now Funding Decision ==== {}'.format(str(trading_date)),
        ui_log)
    if tar1 is None:
        res = None
    else:
        tar2 = tar1[['Z_PROB', 'O_PROB', 'RANK']]
        close = QA_fetch_stock_day_adv(
            list(tar1.index), QA_util_get_last_day(trading_date, 60),
            trading_date).to_qfq().data.loc[trading_date].reset_index(
                'date')['close']
        info = QA_fetch_stock_fianacial_adv(
            list(tar1.index), trading_date,
            trading_date).data.reset_index('date')[['NAME', 'INDUSTRY']]
        res = tar2.join(close).join(info)
        #res = pd.concat([tar2,close,info],axis=1)
        avg_account = sub_accounts['总 资 产'] / tar1.shape[0]
        res = res.assign(tar=avg_account[0] * percent)
        res['cnt'] = (res['tar'] / res['close'] /
                      100).apply(lambda x: round(x, 0) * 100)
        res['real'] = res['cnt'] * res['close']

    QA_util_log_info(
        '##JOB05 Now Current Report ==== {}'.format(str(trading_date)), ui_log)
    table1 = tar[tar['RANK'] <= 5].groupby('date').mean()
    if exceptions is not None:
        frozen_positions = client.get_positions(account1)['positions'][[
            '证券代码', '证券名称', '股票余额', '可用余额', '冻结数量', '参考盈亏', '盈亏比例(%)'
        ]].set_index('证券代码').loc[exceptions]
    else:
        frozen_positions = pd.DataFrame()

    QA_util_log_info(
        '##JOB06 Now Current Holding ==== {}'.format(str(trading_date)),
        ui_log)
    positions = client.get_positions(account1)['positions'][[
        '证券代码', '证券名称', '股票余额', '可用余额', '冻结数量', '参考盈亏', '盈亏比例(%)'
    ]]

    QA_util_log_info(
        '##JOB07 Now Message Building ==== {}'.format(str(trading_date)),
        ui_log)
    try:
        msg1 = '模型训练日期:{model_date}'.format(model_date=stock_info_temp['date'])
        body1 = build_table(
            table1,
            'safe模型结果_{}'.format(str(QA_util_get_last_day(trading_date))))
        body3 = build_table(positions, '目前持仓')
        body4 = build_table(
            pd.DataFrame(report),
            '指数模型结果_{}'.format(str(QA_util_get_last_day(trading_date))))
        body5 = build_table(
            pd.DataFrame(top_report),
            '选股模型结果_{}'.format(str(QA_util_get_last_day(trading_date))))
        #body6 = build_table(stock_list, '上一交易日模型交易清单{}'.format(str(QA_util_get_last_day(trading_date))))
        body7 = build_table(frozen_positions, '目前锁定持仓')
        if res is not None:
            body2 = build_table(res, '目标持仓')
            msg = build_email(build_head(), msg1, body1, body3, body5, body4,
                              body2, body7)
            title = '交易报告'
        else:
            msg = build_email(build_head(), msg1, body1, body3, body5, body4,
                              body1, body7)
            title = '空仓交易报告'
        send_email(title + trading_date, msg, 'date')
    except:
        send_email('交易报告:' + trading_date, "消息构建失败", 'date')
    return (tar)
Esempio n. 30
0
    def get_prices(
        self,
        code_list: Union[str, Tuple[str], List[str]] = None,
        start_time: Union[str, datetime.datetime] = None,
        end_time: Union[str, datetime.datetime] = None,
        fq: str = None,
        frequence: str = None,
        price_type: str = None,
    ):
        """
        价格数据获取接口,单因子输入后,可以通过单因子获取股票代码,时间等参数信息

        参数
        ---
        :param code_list: 股票代码
        :param start_time: 起始时间
        :param end_time: 截止时间
        :param fq: 复权方式
        :param frequence: 时间频率
        """
        # 1. 股票池
        if isinstance(code_list, tuple):
            code_list = list(code_list)

        # 2. 时间频率
        if not frequence:
            frequence = self.frequence
        frequence = utils.get_frequence(frequence)

        if not start_time:
            start_time = self.start_time

        if not end_time:
            end_time = self.end_time

        if (not start_time) or (not end_time):
            raise ValueError("价格获取接口需要指定起始时间与结束时间")

        start_time = str(pd.Timestamp(start_time))[:19]
        end_time = str(pd.Timestamp(end_time))[:19]

        data = QA_fetch_stock_day_adv(code=code_list,
                                      start=start_time,
                                      end=end_time)
        index_data = QA_fetch_index_day_adv(code="000001",
                                            start=start_time,
                                            end=end_time)
        # 3. 复权
        if not fq:
            fq = self.fq

        if not fq:
            data = data
        elif fq.lower() in ["pre", "qfq", "前复权"]:
            data = data.to_qfq()
        elif fq.lower() in ["post", "hfq", "后复权"]:
            data = data.to_hfq()
        elif fq.lower() in ["none", "bfq", "不复权"]:
            data = data

        # 4. 重采样
        # 考虑到停牌退市等原因,重采样会有异常值,即日期与我们需要的日期不一致
        # 这里采用指数作为基准,对重采样数据进行再处理
        # 对于停牌数据缺失,采用前值作为填充
        if frequence == "1d":
            data = data.data.unstack().ffill().stack()
        else:
            index_data = index_data.resample(frequence).unstack()
            data = data.resample(frequence).unstack().ffill()
            data = data.reindex(index_data.index).stack()
            if frequence == '1q':
                data.index = data.index.map(lambda x:
                                            (utils.QA_fmt_quarter(x[0]), x[1]))

        # 5. 价格类型
        if not price_type:
            price_type = self.price_type

        if price_type.lower() is "avg":
            avg = data["amount"] / data["volume"] / 100.0
            return avg.unstack()
        return data[price_type.lower()].unstack()
Esempio n. 31
0
    def __QA_backtest_prepare(self):
        """
        这是模型内部的 初始化,主要是初始化一些账户和市场资产
        写成了私有函数
        @yutiansut
        2017/7/20
        """

        self.strategy_stock_list = np.unique(
            self.strategy_stock_list).tolist()  # 保证不会重复
        if len(str(self.strategy_start_date)) == 10:
            self.strategy_start_time = str(
                self.strategy_start_date) + ' 15:00:00'
        elif len(str(self.strategy_start_date)) == 19:
            self.strategy_start_time = str(self.strategy_start_date)
            self.strategy_start_date = str(self.strategy_start_date)[0:10]
        else:
            self.__QA_backtest_log_info(self, 'Wrong start date format')

        if len(str(self.strategy_end_date)) == 10:
            self.strategy_end_time = str(self.strategy_end_date) + ' 15:00:00'
        elif len(str(self.strategy_end_date)) == 19:
            self.strategy_end_time = str(self.strategy_end_date)
            self.strategy_end_date = str(self.strategy_end_date)[0:10]
        else:
            self.__QA_backtest_log_info(self, 'Wrong end date format')
        # 重新初始账户资产
        self.market = QA_Market(self.commission_fee_coeff)
        self.setting.QA_setting_init()
        self.account.init()
        self.account_d_value.append(self.account.init_assest)
        self.start_real_date = QA_util_get_real_date(self.strategy_start_date,
                                                     self.trade_list, 1)
        self.start_real_time = str(
            self.start_real_date) + ' ' + self.strategy_start_time.split(
                ' ')[1]
        self.start_real_id = self.trade_list.index(self.start_real_date)
        self.end_real_date = QA_util_get_real_date(self.strategy_end_date,
                                                   self.trade_list, -1)
        self.end_real_id = self.trade_list.index(self.end_real_date)
        self.end_real_time = str(self.end_real_date) + \
            ' ' + self.strategy_end_time.split(' ')[1]
        # 重新初始化账户的cookie
        self.account.account_cookie = str(random.random())
        # 初始化股票池的市场数据
        if self.benchmark_type in ['I', 'index']:
            self.benchmark_data = QA_fetch_index_day_adv(
                self.benchmark_code, self.trade_list[self.start_real_id - 1],
                self.end_real_date)
        elif self.benchmark_type in ['S', 'stock']:
            self.benchmark_data = QA_fetch_stock_day_adv(
                self.benchmark_code, self.trade_list[self.start_real_id - 1],
                self.end_real_date)
        if self.backtest_type in ['day', 'd', '0x00']:
            self.market_data = QA_fetch_stocklist_day_adv(
                self.strategy_stock_list,
                self.trade_list[self.start_real_id -
                                int(self.strategy_gap + 1)],
                self.trade_list[self.end_real_id]).to_qfq()

        elif self.backtest_type in ['1min', '5min', '15min', '30min', '60min']:
            self.market_data = QA_fetch_stocklist_min_adv(
                self.strategy_stock_list,
                QA_util_time_gap(self.start_real_time, self.strategy_gap + 1,
                                 '<', self.backtest_type),
                QA_util_time_gap(self.end_real_time, 1, '>',
                                 self.backtest_type),
                self.backtest_type).to_qfq()

        elif self.backtest_type in ['index_day']:
            self.market_data = QA_fetch_index_day_adv(
                self.strategy_stock_list,
                self.trade_list[self.start_real_id -
                                int(self.strategy_gap + 1)],
                self.end_real_date)

        elif self.backtest_type in [
                'index_1min', 'index_5min', 'index_15min', 'index_30min',
                'index_60min'
        ]:
            self.market_data = QA_fetch_index_min_adv(
                self.strategy_stock_list,
                QA_util_time_gap(self.start_real_time, self.strategy_gap + 1,
                                 '<',
                                 self.backtest_type.split('_')[1]),
                QA_util_time_gap(self.end_real_time, 1, '>',
                                 self.backtest_type.split('_')[1]),
                self.backtest_type.split('_')[1])
        self.market_data_dict = dict(
            zip(list(self.market_data.code), self.market_data.splits()))
        self.market_data_hashable = self.market_data.dicts
        self.dirs = '.{}QUANTAXIS_RESULT{}{}{}{}{}'.format(
            os.sep, os.sep, self.topic_name, os.sep, self.stratey_version,
            os.sep)
        os.makedirs(self.dirs, exist_ok=True)
Esempio n. 32
0
 def test_GetItem(self):
     print("ok get item")
     qaDAStruct0 = QA_fetch_stock_day_adv('300439', start="2018-01-01", end="2018-01-10")
     #for iRow int qaDAStruct0.index:
     closePrices = qaDAStruct0.__getitem__('close')
     print(closePrices)
Esempio n. 33
0
 def market_data(self, start, end, _type='day'):
     return QA_fetch_stock_day_adv(self.block_code, start, end)
Esempio n. 34
0
class QA_Risk():
    """QARISK 是一个风险插件

    """
    def __init__(self, account):
        self.account = account
        self.benchmark = None

        self.fetch = {
            MARKET_TYPE.STOCK_CN: QA_fetch_stock_day_adv,
            MARKET_TYPE.INDEX_CN: QA_fetch_index_day_adv
        }
        self.market_data = QA_fetch_stock_day_adv(self.account.code,
                                                  self.account.start_date,
                                                  self.account.end_date)

        self.assets = ((self.market_data.to_qfq().pivot('close') *
                        self.account.daily_hold).sum(axis=1) +
                       self.account.daily_cash.set_index('date').cash).fillna(
                           method='pad')

        self.time_gap = QA_util_get_trade_gap(self.account.start_date,
                                              self.account.end_date)

    def __repr__(self):
        return '< QA_RISK ANALYSIS ACCOUNT-{} >'.format(
            self.account.account_cookie)

    def __call__(self):
        return pd.DataFrame([self.message])

    @property
    def max_dropback(self):
        """最大回撤
        """
        return max([
            self.assets.iloc[idx::].max() - self.assets.iloc[idx::].min()
            for idx in range(len(self.assets))
        ]) / float(self.assets.iloc[0])

    @property
    def profit(self):
        """利润
        """
        return (float(self.assets.iloc[-1]) / float(self.assets.iloc[0])) - 1

    @property
    def annualize_return(self):
        """年化收益

        Returns:
            [type] -- [description]
        """

        return math.pow(
            float(self.assets.iloc[-1]) / float(self.assets.iloc[0]),
            250.0 / float(self.time_gap)) - 1.0

    @property
    def volatility(self):
        """波动率

        Returns:
            [type] -- [description]
        """

        return self.assets.diff().std()

    @property
    def message(self):
        return {
            'account_cookie': self.account.account_cookie,
            'portfolio_cookie': self.account.portfolio_cookie,
            'user_cookie': self.account.user_cookie,
            'annualize_return': self.annualize_return,
            'profit': self.profit,
            'max_dropback': self.max_dropback,
            'time_gap': self.time_gap,
            'volatility': self.volatility
        }

    def set_benchmark(self, code, market_type):
        self.benchmark = self.fetch[market_type](code, self.account.start_date,
                                                 self.account.end_date)
Esempio n. 35
0
class QA_Risk():
    """QARISK 是一个风险插件

    需要加载一个account/portfolio类进来:
    需要有
    code,start_date,end_date,daily_cash,daily_hold

    TODO:
    资金利用率 反应资金的利用程度
    股票周转率 反应股票的持仓天数
    预期PNL/统计学PNL
    """

    def __init__(self, account, benchmark_code='000300', benchmark_type=MARKET_TYPE.INDEX_CN, if_fq=True):
        """
        if_qf选项是@尧提出的,关于回测的时候成交价格问题(如果按不复权撮合 应该按不复权价格计算assets)
        """
        self.account = account
        self.benchmark_code = benchmark_code  # 默认沪深300
        self.benchmark_type = benchmark_type

        self.fetch = {MARKET_TYPE.STOCK_CN: QA_fetch_stock_day_adv,
                      MARKET_TYPE.INDEX_CN: QA_fetch_index_day_adv}
        self.market_data = QA_fetch_stock_day_adv(
            self.account.code, self.account.start_date, self.account.end_date)
        self.if_fq = if_fq

        self._assets = (self.market_value.sum(
            axis=1) + self.account.daily_cash.set_index('date').cash).fillna(method='pad')

        self.time_gap = QA_util_get_trade_gap(
            self.account.start_date, self.account.end_date)
        self.init_cash = self.account.init_cash
        self.init_assets = self.account.init_assets

    def __repr__(self):
        return '< QA_RISK ANALYSIS ACCOUNT/PORTFOLIO >'

    def __call__(self):
        return pd.DataFrame([self.message])

    @property
    @lru_cache()
    def market_value(self):
        """市值表

        Returns:
            pd.DataFrame -- 市值表
        """

        if self.if_fq:
            return self.market_data.to_qfq().pivot('close') * self.account.daily_hold
        else:
            self.market_data.pivot('close') * self.account.daily_hold

    @property
    def assets(self):
        x1 = self._assets.reset_index()
        return x1.assign(date=pd.to_datetime(x1.date)).set_index('date')[0]

    @property
    def max_dropback(self):
        """最大回撤
        """
        return round(float(max([(self.assets.iloc[idx] - self.assets.iloc[idx::].min())/self.assets.iloc[idx] for idx in range(len(self.assets))])), 2)

    @property
    def total_commission(self):
        """总手续费
        """
        return -abs(round(self.account.history_table.commission.sum(), 2))

    @property
    def total_tax(self):
        """总印花税

        """

        return -abs(round(self.account.history_table.tax.sum(), 2))

    @property
    def profit_construct(self):
        """利润构成

        Returns:
            dict -- 利润构成表
        """

        return {
            'total_buyandsell': round(self.profit_money-self.total_commission-self.total_tax, 2),
            'total_tax': self.total_tax,
            'total_commission': self.total_commission,
            'total_profit': self.profit_money
        }

    @property
    def profit_money(self):
        """盈利额

        Returns:
            [type] -- [description]
        """

        return round(self.assets.iloc[-1]-self.init_cash, 2)

    @property
    def profit(self):
        """盈利率(百分比)

        Returns:
            [type] -- [description]
        """

        return round(float(self.calc_profit(self.assets)), 2)

    @property
    def profit_pct(self):
        """利润
        """
        return self.calc_profitpctchange(self.assets)

    @property
    def annualize_return(self):
        """年化收益

        Returns:
            [type] -- [description]
        """

        return round(float(self.calc_annualize_return(self.assets, self.time_gap)), 2)

    @property
    def volatility(self):
        """波动率

        Returns:
            [type] -- [description]
        """
        return round(float(self.profit_pct.std() * math.sqrt(250)), 2)

    @property
    @lru_cache()
    def message(self):
        return {
            'account_cookie': self.account.account_cookie,
            'portfolio_cookie': self.account.portfolio_cookie,
            'user_cookie': self.account.user_cookie,
            'annualize_return': round(self.annualize_return, 2),
            'profit': round(self.profit, 2),
            'max_dropback': self.max_dropback,
            'time_gap': self.time_gap,
            'volatility': self.volatility,
            'benchmark_code': self.benchmark_code,
            'bm_annualizereturn': self.benchmark_annualize_return,
            'bn_profit': self.benchmark_profit,
            'beta': self.beta,
            'alpha': self.alpha,
            'sharpe': self.sharpe,
            'init_cash': "%0.2f" % (float(self.init_cash)),
            'last_assets': "%0.2f" % (float(self.assets.iloc[-1]))

            #'init_assets': round(float(self.init_assets), 2),
            #'last_assets': round(float(self.assets.iloc[-1]), 2)
        }

    @property
    def benchmark_data(self):
        """
        基准组合的行情数据(一般是组合,可以调整)
        """
        return self.fetch[self.benchmark_type](
            self.benchmark_code, self.account.start_date, self.account.end_date)

    @property
    def benchmark_assets(self):
        """
        基准组合的账户资产队列
        """
        return (self.benchmark_data.close / float(self.benchmark_data.open.iloc[0]) * float(self.init_cash))

    @property
    def benchmark_profit(self):
        """
        基准组合的收益
        """
        return round(float(self.calc_profit(self.benchmark_assets)), 2)

    @property
    def benchmark_annualize_return(self):
        """基准组合的年化收益

        Returns:
            [type] -- [description]
        """

        return round(float(self.calc_annualize_return(self.benchmark_assets, self.time_gap)), 2)

    @property
    def benchmark_profitpct(self):
        """
        benchmark 基准组合的收益百分比计算
        """
        return self.calc_profitpctchange(self.benchmark_assets)

    @property
    def beta(self):
        """
        beta比率 组合的系统性风险
        """
        return round(float(self.calc_beta(self.profit_pct.dropna(), self.benchmark_profitpct.dropna())), 2)

    @property
    def alpha(self):
        """
        alpha比率 与市场基准收益无关的超额收益率
        """
        return round(float(self.calc_alpha(self.annualize_return, self.benchmark_annualize_return, self.beta, 0.05)), 2)

    @property
    def sharpe(self):
        """
        夏普比率

        """
        return round(float(self.calc_sharpe(self.annualize_return, self.volatility, 0.05)), 2)

    @property
    def sortino(self):
        """ 
        索提诺比率 投资组合收益和下行风险比值

        """
        pass

    @property
    def calmar(self):
        """
        卡玛比率
        """
        pass

    def set_benchmark(self, code, market_type):
        self.benchmark_code = code
        self.benchmark_type = market_type

    def calc_annualize_return(self, assets, days):
        return round((float(assets.iloc[-1]) / float(assets.iloc[0]) - 1)/(float(days) / 250), 2)

    def calc_profitpctchange(self, assets):
        return self.assets[::-1].pct_change()

    def calc_beta(self, assest_profit, benchmark_profit):

        calc_cov = np.cov(assest_profit, benchmark_profit)
        beta = calc_cov[0, 1] / calc_cov[1, 1]
        return beta

    def calc_alpha(self, annualized_returns, benchmark_annualized_returns, beta, r=0.05):

        alpha = (annualized_returns - r) - (beta) * \
            (benchmark_annualized_returns - r)
        return alpha

    def calc_profit(self, assets):
        """
        计算账户收益
        期末资产/期初资产 -1
        """
        return (float(assets.iloc[-1]) / float(self.init_cash)) - 1

    def calc_sharpe(self, annualized_returns, volatility_year, r=0.05):
        """
        计算夏普比率
        r是无风险收益
        """
        # 会出现0
        if volatility_year == 0:
            return 0
        return (annualized_returns - r) / volatility_year

    def save(self):
        """save to mongodb

        """
        save_riskanalysis(self.message)

    def plot_assets_curve(self, length=14, height=12):
        """
        资金曲线叠加图
        @Roy T.Burns 2018/05/29 修改百分比显示错误
        """
        plt.style.use('ggplot')
        plt.figure(figsize=(length, height))
        plt.subplot(211)
        plt.title('BASIC INFO', fontsize=12)
        plt.axis([0, length, 0, 0.6])
        plt.axis('off')
        i = 0
        for item in ['account_cookie', 'portfolio_cookie', 'user_cookie']:
            plt.text(i, 0.5, '{} : {}'.format(
                item, self.message[item]), fontsize=10, rotation=0, wrap=True)
            i += (length/2.8)
        i = 0
        for item in ['benchmark_code', 'time_gap', 'max_dropback']:
            plt.text(i, 0.4, '{} : {}'.format(
                item, self.message[item]), fontsize=10, ha='left', rotation=0, wrap=True)
            i += (length/2.8)
        i = 0
        for item in ['annualize_return', 'bm_annualizereturn', 'profit']:
            plt.text(i, 0.3, '{} : {} %'.format(item, self.message.get(
                item, 0)*100), fontsize=10, ha='left', rotation=0, wrap=True)
            i += length/2.8
        i = 0
        for item in ['init_cash', 'last_assets', 'volatility']:
            plt.text(i, 0.2, '{} : {} '.format(
                item, self.message[item]), fontsize=10, ha='left', rotation=0, wrap=True)
            i += length/2.8
        i = 0
        for item in ['alpha', 'beta', 'sharpe']:
            plt.text(i, 0.1, '{} : {}'.format(
                item, self.message[item]), ha='left', fontsize=10, rotation=0, wrap=True)
            i += length/2.8
        plt.subplot(212)
        self.assets.plot()
        self.benchmark_assets.xs(self.benchmark_code, level=1).plot()

        asset_p = mpatches.Patch(
            color='red', label='{}'.format(self.account.account_cookie))
        asset_b = mpatches.Patch(
            label='benchmark {}'.format(self.benchmark_code))
        plt.legend(handles=[asset_p, asset_b], loc=1)
        plt.title('ASSET AND BENCKMARK')
        plt.show()

    def plot_dailyhold(self, start=None, end=None):
        """
        使用热力图画出每日持仓
        """
        start = self.account.start_date if start is None else start
        end = self.account.end_date if end is None else end
        _, ax = plt.subplots(figsize=(20, 8))
        sns.heatmap(self.account.daily_hold.reset_index().drop('account_cookie', axis=1).set_index(
            'date').loc[start:end], cmap="YlGnBu", linewidths=0.05, ax=ax)
        ax.set_title(
            'HOLD TABLE --ACCOUNT: {}'.format(self.account.account_cookie))
        ax.set_xlabel('Code')
        ax.set_ylabel('DATETIME')
        plt.show()

    def plot_signal(self, start=None, end=None):
        """
        使用热力图画出买卖信号
        """
        start = self.account.start_date if start is None else start
        end = self.account.end_date if end is None else end
        _, ax = plt.subplots(figsize=(20, 18))
        sns.heatmap(self.account.trade.reset_index().drop('account_cookie', axis=1).set_index(
            'datetime').loc[start:end], cmap="YlGnBu", linewidths=0.05, ax=ax)
        ax.set_title(
            'SIGNAL TABLE --ACCOUNT: {}'.format(self.account.account_cookie))
        ax.set_xlabel('Code')
        ax.set_ylabel('DATETIME')
        plt.show()

    def generate_plots(self):
        """
        生成图像
        """
        self.plot_assets_curve()
        self.plot_dailyhold()
        self.plot_signal()
Esempio n. 36
0
class QA_Risk():
    """QARISK 是一个风险插件

    需要加载一个account/portfolio类进来:
    需要有
    code,start_date,end_date,daily_cash,daily_hold
    """
    def __init__(self,
                 account,
                 benchmark_code='000300',
                 benchmark_type=MARKET_TYPE.INDEX_CN):
        self.account = account
        self.benchmark_code = benchmark_code  # 默认沪深300
        self.benchmark_type = benchmark_type

        self.fetch = {
            MARKET_TYPE.STOCK_CN: QA_fetch_stock_day_adv,
            MARKET_TYPE.INDEX_CN: QA_fetch_index_day_adv
        }
        self.market_data = QA_fetch_stock_day_adv(self.account.code,
                                                  self.account.start_date,
                                                  self.account.end_date)

        self.assets = ((self.market_data.to_qfq().pivot('close') *
                        self.account.daily_hold).sum(axis=1) +
                       self.account.daily_cash.set_index('date').cash).fillna(
                           method='pad')

        self.time_gap = QA_util_get_trade_gap(self.account.start_date,
                                              self.account.end_date)
        self.init_assets = self.account.init_assets

    def __repr__(self):
        return '< QA_RISK ANALYSIS ACCOUNT/PORTFOLIO >'

    def __call__(self):
        return pd.DataFrame([self.message])

    @property
    def max_dropback(self):
        """最大回撤
        """
        return max([
            self.assets.iloc[idx::].max() - self.assets.iloc[idx::].min()
            for idx in range(len(self.assets))
        ]) / float(self.assets.iloc[0])

    @property
    def profit(self):
        return self.calc_profit(self.assets)

    @property
    def profit_pct(self):
        """利润
        """
        return self.calc_profitpctchange(self.assets)

    @property
    def annualize_return(self):
        """年化收益

        Returns:
            [type] -- [description]
        """

        return self.calc_annualize_return(self.assets, self.time_gap)

    @property
    def volatility(self):
        """波动率

        Returns:
            [type] -- [description]
        """
        return self.profit_pct.std() * math.sqrt(250)

    @property
    def message(self):
        return {
            'account_cookie': self.account.account_cookie,
            'portfolio_cookie': self.account.portfolio_cookie,
            'user_cookie': self.account.user_cookie,
            'annualize_return': self.annualize_return,
            'profit': self.profit,
            'max_dropback': self.max_dropback,
            'time_gap': self.time_gap,
            'volatility': self.volatility,
            'benchmark_code': self.benchmark_code,
            'beta': self.beta,
            'alpha': self.alpha,
            'sharpe': self.sharpe,
            'init_assets': self.init_assets,
            'last_assets': self.assets.iloc[-1]
        }

    @property
    def benchmark_data(self):
        """
        基准组合的行情数据(一般是组合,可以调整)
        """
        return self.fetch[self.benchmark_type](self.benchmark_code,
                                               self.account.start_date,
                                               self.account.end_date)

    @property
    def benchmark_assets(self):
        """
        基准组合的账户资产队列
        """
        return (self.benchmark_data.open /
                float(self.benchmark_data.open.iloc[0]) *
                float(self.init_assets))

    @property
    def benchmark_annualize_return(self):
        """基准组合的年化收益

        Returns:
            [type] -- [description]
        """

        return self.calc_annualize_return(self.benchmark_assets, self.time_gap)

    @property
    def benchmark_profitpct(self):
        """
        benchmark 基准组合的收益百分比计算
        """
        return self.calc_profitpctchange(self.benchmark_assets)

    @property
    def beta(self):
        """
        beta比率 组合的系统性风险
        """
        return self.calc_beta(self.profit_pct.dropna(),
                              self.benchmark_profitpct.dropna())

    @property
    def alpha(self):
        """
        alpha比率 与市场基准收益无关的超额收益率
        """
        return self.calc_alpha(self.annualize_return,
                               self.benchmark_annualize_return, self.beta,
                               0.05)

    @property
    def sharpe(self):
        """
        夏普比率

        """
        return self.calc_sharpe(self.annualize_return, self.volatility, 0.05)

    @property
    def sortino(self):
        """ 
        索提诺比率 投资组合收益和下行风险比值

        """
        pass

    @property
    def calmar(self):
        """
        卡玛比率
        """
        pass

    def set_benchmark(self, code, market_type):
        self.benchmark_code = code
        self.benchmark_type = market_type

    def calc_annualize_return(self, assets, days):
        return (float(assets.iloc[-1]) / float(assets.iloc[0]) -
                1) / (float(days) / 250)

    def calc_profitpctchange(self, assets):
        return self.assets[::-1].pct_change()

    def calc_beta(self, assest_profit, benchmark_profit):

        calc_cov = np.cov(assest_profit, benchmark_profit)
        beta = calc_cov[0, 1] / calc_cov[1, 1]
        return beta

    def calc_alpha(self,
                   annualized_returns,
                   benchmark_annualized_returns,
                   beta,
                   r=0.05):

        alpha = (annualized_returns - r) - (beta) * \
            (benchmark_annualized_returns - r)
        return alpha

    def calc_profit(self, assets):
        """
        计算账户收益
        期末资产/期初资产 -1
        """
        return (float(assets.iloc[-1]) / float(assets.iloc[0])) - 1

    def calc_sharpe(self, annualized_returns, volatility_year, r=0.05):
        """
        计算夏普比率
        r是无风险收益
        """
        return (annualized_returns - r) / volatility_year

    def save(self):
        """save to mongodb

        """
        save_riskanalysis(self.message)