コード例 #1
0
ファイル: Divide.py プロジェクト: dxcv/GsEnv
def Divide(otv1, otv2):
    otv1 = otv1.asMatrix()
    otv2 = otv2.asMatrix()
    try:
        common_index = np.intersect1d(otv1.index, otv2.index)
        otv1 = otv1.reindex(common_index)
        otv2 = otv2.reindex(common_index)
        col_num1 = len(otv1.columns)
        col_num2 = len(otv2.columns)
        if col_num1 == 1 and otv1.columns[0] == gsUtils.getGodGid(
        ) and col_num2 != 1:
            tmp = np.tile(otv1, col_num2)
            output = tmp / otv2
        elif col_num1 != 1 and col_num2 == 1 and otv2.columns[
                0] == gsUtils.getGodGid():
            tmp = np.tile(otv2, col_num1)
            output = otv1 / tmp
        else:
            output = otv1 / tmp
    except:
        output = otv1 / otv2
    try:
        output = output.dropna(axis=[0, 1], how='all')
    except:
        pass
    return output
コード例 #2
0
def convex_optimizer(context,mode,position_limit,forecast_return,original_portfolio,target_risk,target_return,X,covariance_matrix,delta,constraint):
    '''
    optimize fund weight target on different constraints, objective, based on
    target type and mode, fund return target, fund weight, group weight, etc.

    Parameters
    ----------
    mode: dictionary
        target optimization type({type: mode})
        0: minimum risk.
        1: minimum risk subject to target return.
        2: maximum return subject to target risk.

    original_portfolio: OOTV
        input original waiting for optimization

    forecast_return: Dataframe, OTV,
        asset return for all symbols.
        index=date, O: asset names, V: asset return.

    target_return: double
        Target return for portfolio respected to benchmark.

    target_risk: double
        Portfolio risk tolerance whose objective is maximum return.

    cov_matrix: OOTV
        covariance matrix from risk model if holdings are stocks.

    X: pandas panel
        factor exposure

    delta: OOTV
        specific risk, diagonal matrix

    constraint: dictionaries tuples
        dictionary: OOTV, OTVV

    Returns
    -------
    df_result: DataFrame
        Optimized value of weight.
        Index: target date.
        Columns: assets names.
    '''
    # create logger
    logger = logging.getLogger()
    handler = logging.StreamHandler()
    formatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
    handler.setFormatter(formatter)
    if not logger.handlers:
        logger.addHandler(handler)
    logger.setLevel(logging.DEBUG)


    # convert gft table to pandas dataframe
    if isinstance(original_portfolio, gftIO.GftTable):
        original_portfolio = original_portfolio.asColumnTab()
    if isinstance(forecast_return, gftIO.GftTable):
        forecast_return = forecast_return.asMatrix()
    if isinstance(covariance_matrix, gftIO.GftTable):
        covariance_matrix = covariance_matrix.asColumnTab().copy()
        # extra action in case the index is set as date in the function asColumnTab
        try:
            covariance_matrix.set_index('date', inplace=True)
        except:
            pass

    if isinstance(delta, gftIO.GftTable):
        delta = delta.asMatrix()

    all_factors_gid = covariance_matrix['factorid1'].unique()

    df_industries_asset_weight = original_portfolio.dropna(
        axis=0, subset=['industry', 'symbol'], how='any')

    datetime_index = pd.DatetimeIndex(df_industries_asset_weight['date'].unique())
    target_date = datetime_index[0]

    # get unique symbols from the portfolio
    unique_symbol = df_industries_asset_weight['symbol'].unique()

    # create dataframe for output
    df_opts_weight = pd.DataFrame(data=np.nan, columns=unique_symbol,
                                  index=datetime_index)
    df_opts_status = pd.DataFrame(data=np.nan, columns=gsUtils.getGodGid(),
                                  index=datetime_index)

    for target_date in datetime_index:
        logger.debug('target date: %s', target_date)
        # only select those intersection assets between unique symbol and symbols in delta on target date.
        try:
            target_assets = delta.loc[target_date].index.intersection(unique_symbol)
        except KeyError as e:
            logger.debug(e.args)
            # fill the weight with previous value if error.
            df_opts_weight.fillna(method='pad', inplace=True)
            df_opts_status.loc[target_date] = gsConst.Const.Infeasible
            continue
        # select the number of position limit ranked symbols by requested mode.
        if mode == gsConst.Const.MinimumRiskUnderReturn:
            target_assets = forecast_return.loc[:target_date, target_assets].fillna('pad').std().sort_values(ascending=False)[:position_limit].index
        else:
            target_assets = forecast_return.loc[target_date,target_assets].sort_values(ascending=False)[:position_limit].index

        noa = len(target_assets)
        logger.debug('target assets: %s', target_assets.shape)

        # use the mean return prior target date as the predicted return temperarily
        # will use the forecasted return as ultimate goal
        rets_mean = forecast_return.loc[target_date, target_assets]

        # get delta on the target date, which is a diagonal matrix
        diag = delta.loc[target_date, target_assets]
        delta_on_date = pd.DataFrame(np.diag(diag), index=diag.index,
                                     columns=diag.index).fillna(0)

        # get covariance matrix, re-index from the list of all factors' gid
        cov_matrix = covariance_matrix.loc[target_date]
        cov_matrix = cov_matrix.pivot(index='factorid1', columns='factorid2', values='value')
        cov_matrix = cov_matrix.reindex(all_factors_gid, all_factors_gid, fill_value=np.nan)

        # big X is sigma in the quadratic equation, size = 35 * number of assets
        big_X = X.loc[target_date]
        big_X = big_X.loc[target_assets]
        big_X = big_X.reindex(columns=all_factors_gid)
        big_X.fillna(0,inplace=True)

        # setup the Factor model portfolio optimization parameter
        # w is the solution x variable
        w = cvx.Variable(noa)
        f = big_X.T.values*w

        # gamma parameter, multiplier of risk
        gamma = cvx.Parameter(sign='positive')
        # Lmax is maximum leverage
        Lmax = cvx.Parameter()
        ret = w.T * rets_mean.values

        # create quadratic form of risk
        risk = cvx.quad_form(f, cov_matrix.values) + cvx.quad_form(w, delta_on_date.values)

        # setup value constraint:
        """
        # asset constraint:
        Asset ts_asset_group_loading diagonal matrix:(OOTV, Matrix M1(n * n)), 59 * 59.
        asset value range, value1, value2, 58 * 2.
        select 58 * 58 from diagonal matrix, order by idx_leve1_value.
        product: multiply_matrix.T.values * w, [58x58] * [58x1]

        # industry constraint:
        industry ts_asset_group_loading sparse matrix:(OOTV, Matrix M1(n * m)), 58 * 26.
        industry value range, value1, value2, 26 * 2.
        select 58 * 26 from sparse matrix, order by group_constraint index value.
        product: multiply_matrix.T.values * w, [26x58] * [58x1]=[26x1]

        # factor constraint:
        factor ts_asset_group_loading exposure matrix:(OOTV, Matrix M1(n * m)), 35 * 3436.
        factor exposure value range, value1, value2, 35 * 2.
        select 35 * 58 from factor exposure matrix.
        product: multiply_matrix.T.values * w, [35x58] * [58x1]=[35x1]
        """
        constraint_value = []
        for cst in constraint:
            if cst is None:
                continue
            # in order to align the production.
            df_boundary = cst['ts_group_loading_range'].asColumnTab().copy()
            df_boundary = df_boundary.loc[(df_boundary['date'] == target_date)]
            df_boundary.drop('date', axis=1, inplace=True)
            df_boundary.set_index('target', inplace=True)
            df_boundary_idx = df_boundary.index

            multiply_matrix = cst['ts_asset_group_loading'].copy().\
                                  loc[target_date].loc[target_assets,
                                                       df_boundary_idx].fillna(0)

            create_constraint(multiply_matrix.T.values*w,
                              df_boundary, constraint_value)

        # leverage level and risk adjusted parameter
        Lmax.value = 1
        gamma.value = 1
        eq_constraint = [cvx.sum_entries(w) == 1,
                         cvx.norm(w, 1) <= Lmax]
        if mode == gsConst.Const.MinimumRisk:
            # maximize negative product of gamma and risk
            prob_factor = cvx.Problem(cvx.Maximize(-gamma*risk),
                                      eq_constraint + constraint_value)
        if mode == gsConst.Const.MinimumRiskUnderReturn:
            # minimum risk subject to target return, Markowitz Mean_Variance Portfolio
            prob_factor = cvx.Problem(cvx.Maximize(-gamma*risk),
                                      [ret >= target_return]+eq_constraint+constraint_value)
        if mode == gsConst.Const.MaximumReturnUnderRisk:
            # Portfolio optimization with a leverage limit and a bound on risk
            prob_factor = cvx.Problem(cvx.Maximize(ret),
                                      [risk <= target_risk]+eq_constraint+constraint_value)
        prob_factor.solve(verbose=False)
        logger.debug(prob_factor.status)
        if prob_factor.status == 'infeasible':
            df_opts_status.loc[target_date] = gsConst.Const.Infeasible
        else:
            df_opts_weight.loc[target_date, target_assets] = np.array(w.value.astype(np.float64)).T
            df_opts_status.loc[target_date] = gsConst.Const.Feasible

    return {'weight':df_opts_weight.dropna(axis=0, how='all'), 'status':df_opts_status}
コード例 #3
0
def SIMPLE_SIMULATE_DAILY_TRADE_CHN_STK(beginDate, endDate, initialHolding,
                                        df_targetPortfolioWgt,
                                        df_markToMarketPrice,
                                        df_totalReturnFactor, df_executePrice,
                                        df_execPriceReturn, df_tradeVolume,
                                        dict_tradingParam, dict_additionalTs):
    beginDate = beginDate[0]
    endDate = endDate[0]
    df_targetPortfolioWgt = df_targetPortfolioWgt.asMatrix()
    df_markToMarketPrice = df_markToMarketPrice.asMatrix()
    df_totalReturnFactor = df_totalReturnFactor.asMatrix()
    df_executePrice = df_executePrice.asMatrix()
    df_execPriceReturn = df_execPriceReturn.asMatrix()
    df_tradeVolume = df_tradeVolume.asMatrix()
    cashSymbol = gsUtils.getCashGid()
    godGid = gsUtils.getGodGid()

    allDates = df_markToMarketPrice.index
    if len(allDates[(allDates >= beginDate) & (allDates <= endDate)]) < 1:
        raise ValueError('no trading date falls between begindate and enddate')
    endDate = allDates[allDates <= endDate][-1]
    if beginDate > endDate:
        raise ValueError('beginDate should be less than endDate')

    initHldIsCash = True
    if isinstance(initialHolding, gftIO.GftTable):
        df_initialHolding = initialHolding.asMatrix()
        if df_initialHolding.shape[0] < 1:
            raise ValueError('no init holding is provided')
        initHldIsCash = False
        df_initialHolding = df_initialHolding.ix[-1:]
        beginDate = gsUtils.alignDate(df_initialHolding.index[0],
                                      allDates,
                                      method='ffill')
        if pd.isnull(beginDate):
            raise ValueError('do not have close price for the date of initHld')
        df_initialHolding.index = [beginDate]
    else:
        beginDate = gsUtils.alignDate(beginDate, allDates, method='bfill')
        if pd.isnull(beginDate):
            raise ValueError(
                'beginDate should be less than the last trading date')

    if (df_targetPortfolioWgt < 0).any(axis=1).any():
        raise ValueError(
            'Do not support stock short selling and cash borrowing')
    if (round(df_targetPortfolioWgt.sum(1), 4) > 1).any():
        raise ValueError('Total weight is greater than 1.')
    df_targetPortfolioWgt = df_targetPortfolioWgt.dropna(axis=[0, 1],
                                                         how='all')
    sigDates = df_targetPortfolioWgt.index
    rebDates = sigDates
    if len(sigDates) > 0:
        execDelayPeriods = gsUtils.getParm(dict_tradingParam,
                                           "execDelayPeriods", 0)
        if execDelayPeriods > 0:
            idxs = np.array(gsUtils.alignDate(sigDates,
                                              allDates,
                                              method='bfill',
                                              returnidx=True),
                            dtype=float)
            idxs = idxs + execDelayPeriods
            idxs[idxs > len(allDates)] = NA
            idxs[idxs == np.append(idxs[1:], NA)] = NA
            idxs_nonnan_flag = np.logical_not(np.isnan(idxs))
            if sum(idxs_nonnan_flag) < 1:
                raise ValueError("no trade date after the execute delay shift")
            df_targetPortfolioWgt = df_targetPortfolioWgt.ix[idxs_nonnan_flag]
            rebDates = allDates[np.array(idxs[idxs_nonnan_flag], dtype=int)]
            df_targetPortfolioWgt.index = rebDates
        if len(rebDates) > 0:
            if initHldIsCash:
                if gsUtils.getParm(dict_tradingParam, "shiftBeginDateToSignal",
                                   False):
                    beginDate = rebDates[rebDates >= beginDate][0]
                if pd.isnull(beginDate):
                    raise ValueError('beginDate is null after shift')

    tradeDates = allDates[(allDates >= beginDate) & (allDates <= endDate)]
    beginDate = tradeDates[0]
    endDate = tradeDates[-1]
    if beginDate > endDate:
        raise ValueError(
            "Begin date is larger than end date after the date processing!")
    rebDates = rebDates[(rebDates >= beginDate) & (rebDates <= endDate)]
    df_targetPortfolioWgt = df_targetPortfolioWgt.ix[rebDates]

    allSymbols = np.unique(df_markToMarketPrice.columns)
    portfolioSymbols = np.unique(
        np.setdiff1d(df_targetPortfolioWgt.columns, cashSymbol))
    holdingSymbols = np.array([])
    if not (initHldIsCash):
        holdingSymbols = np.unique(
            np.setdiff1d(df_initialHolding.columns, cashSymbol))
    if len(np.setdiff1d(holdingSymbols, allSymbols)) > 0:
        raise ValueError("Initial Portfolio has non A-share stocks!")
    if len(np.setdiff1d(portfolioSymbols, allSymbols)) > 0:
        raise ValueError("Target Portfolio has non A-share stocks!")

    allSymbols = np.unique(
        np.setdiff1d(
            np.intersect1d(allSymbols,
                           np.append(holdingSymbols, portfolioSymbols)),
            cashSymbol))
    priceDates = allDates[(allDates >= beginDate - datetime.timedelta(days=20))
                          & (allDates <= endDate)]

    df_markToMarketPrice = df_markToMarketPrice.reindex(priceDates,
                                                        allSymbols,
                                                        fill_value=NA)
    df_totalReturnFactor = df_totalReturnFactor.reindex(
        priceDates, allSymbols, fill_value=1.).fillna(1.)
    df_executePrice = df_executePrice.reindex(priceDates,
                                              allSymbols,
                                              fill_value=NA)
    df_execPriceReturn = df_execPriceReturn.reindex(priceDates,
                                                    allSymbols,
                                                    fill_value=NA)
    df_tradeVolume = df_tradeVolume.reindex(priceDates,
                                            allSymbols,
                                            fill_value=0.)

    if initHldIsCash:
        df_initialHolding = pd.DataFrame(initialHolding,
                                         index=[beginDate],
                                         columns=[cashSymbol])
    df_initialHolding = df_initialHolding.reindex(
        columns=np.append(allSymbols, cashSymbol)).fillna(0.)
    df_initialHoldingCash = df_initialHolding.ix[:, cashSymbol]
    df_initialHolding = df_initialHolding.ix[:, allSymbols]
    initHldValue = float(
        (df_initialHolding * df_markToMarketPrice.ix[df_initialHolding.index]
         ).sum(axis=1)) + df_initialHoldingCash.ix[0, 0]

    df_targetPortfolioWgt = df_targetPortfolioWgt.reindex(
        rebDates, allSymbols, fill_value=0.).fillna(0.)

    df_buyVolume = df_tradeVolume.copy().fillna(0)
    df_sellVolume = df_buyVolume.copy()
    if gsUtils.getParm(dict_tradingParam, "canTradeOnSuspend", 0) > 0:
        df_buyVolume[df_buyVolume < 1] = np.inf
        df_sellVolume[df_sellVolume < 1] = np.inf
    riseLimitThres = gsUtils.getParm(dict_tradingParam, "riseLimitThres", 0)
    if riseLimitThres > 0:
        riseLimit = df_execPriceReturn > riseLimitThres
        df_buyVolume[riseLimit] = 0
        df_sellVolume[riseLimit & (df_sellVolume > 0)] = np.inf
    fallLimitThres = gsUtils.getParm(dict_tradingParam, "fallLimitThres", 0)
    if fallLimitThres < 0:
        fallLimit = df_execPriceReturn < fallLimitThres
        df_buyVolume[fallLimit & (df_buyVolume > 0)] = np.inf
        df_sellVolume[fallLimit] = 0
    volumeLimitPct = gsUtils.getParm(dict_tradingParam, "volumeLimitPct", 0)
    if volumeLimitPct > 0:
        df_buyVolume = df_buyVolume * volumeLimitPct
        df_sellVolume = df_sellVolume * volumeLimitPct
    else:
        df_buyVolume[df_buyVolume > 0] = np.inf
        df_sellVolume[df_sellVolume > 0] = np.inf

    lotSize = gsUtils.getParm(dict_tradingParam, "lotSize", 0)
    df_buyVolume = gsUtils.roundToLot(df_buyVolume, lotSize)
    df_sellVolume = gsUtils.roundToLot(df_sellVolume, lotSize)

    buyCommission = gsUtils.getParm(dict_tradingParam, "buyCommission", 0)
    sellCommission = gsUtils.getParm(dict_tradingParam, "sellCommission", 0)

    df_holdings = pd.DataFrame(0., index=tradeDates, columns=allSymbols)
    df_weights = df_holdings.copy()
    df_execution = df_holdings.copy()
    df_holdingCash = pd.DataFrame(0., index=tradeDates, columns=cashSymbol)
    df_portfolioValue = pd.DataFrame(0., index=tradeDates, columns=godGid)
    df_cumRets = df_portfolioValue.copy()
    df_singlePeriodRets = df_portfolioValue.copy()
    df_turnoverPct = df_portfolioValue.copy()

    d = tradeDates[0]
    df_holdings.ix[d] = df_initialHolding.ix[d]
    df_holdingCash.ix[d] = df_initialHoldingCash.ix[0, 0]
    if len(rebDates) < 1:
        nextd = tradeDates[-1]
        ls_adjustedHoldings = fillHolding(d, nextd, tradeDates, df_holdings,
                                          df_holdingCash, df_totalReturnFactor)
        df_holdings = ls_adjustedHoldings['holdings']
        df_holdingCash = ls_adjustedHoldings['holdingCash']
    else:
        nextd = rebDates[0]
        ls_adjustedHoldings = fillHolding(d, nextd, tradeDates, df_holdings,
                                          df_holdingCash, df_totalReturnFactor)
        df_holdings = ls_adjustedHoldings['holdings']
        df_holdingCash = ls_adjustedHoldings['holdingCash']
        for i in range(len(rebDates)):
            d = rebDates[i]
            s_currentHoldingValue = df_holdings.ix[d] * df_executePrice.ix[d]
            totalValue = s_currentHoldingValue.sum() + df_holdingCash.ix[d, 0]
            s_currentHoldingWgt = s_currentHoldingValue / totalValue
            s_targetHoldingWgt = df_targetPortfolioWgt.ix[d]
            targetHoldingCashWgt = 1.0 - s_targetHoldingWgt.sum()
            s_orderWgt = s_targetHoldingWgt - s_currentHoldingWgt
            s_sellOrderWgt = s_orderWgt.copy()
            s_sellOrderWgt[s_sellOrderWgt > 0.] = 0.
            s_buyOrderWgt = s_orderWgt.copy()
            s_buyOrderWgt[s_buyOrderWgt < 0.] = 0.
            cashAvail = df_holdingCash.ix[d, 0]
            if (s_sellOrderWgt < 0).any():
                s_sellOrder = gsUtils.roundToLot(
                    s_sellOrderWgt /
                    s_currentHoldingWgt.where(s_currentHoldingWgt > 0, 1.0) *
                    df_holdings.ix[d], lotSize)
                s_sellOrder = s_sellOrder.where(s_targetHoldingWgt > 0,
                                                -df_holdings.ix[d])
                s_sellExecution = s_sellOrder.copy()
                s_sellExecution = -pd.concat(
                    [s_sellExecution.fillna(0).abs(), df_sellVolume.ix[d]],
                    axis=1).min(axis=1)
                cashAvail = cashAvail + (s_sellExecution.abs(
                ) * df_executePrice.ix[d]).sum() * (1 - sellCommission)
                df_execution.ix[d] += s_sellExecution
                df_holdings.ix[d] += s_sellExecution
            if (s_buyOrderWgt > 0).any():
                canBuyWgt = cashAvail / totalValue - targetHoldingCashWgt
                if canBuyWgt > 0:
                    s_buyOrder = gsUtils.roundToLot(
                        (min(canBuyWgt / s_buyOrderWgt.sum(), 1.0) *
                         s_buyOrderWgt * totalValue / (1 + buyCommission) /
                         df_executePrice.ix[d]).fillna(0), lotSize)
                    s_buyExecution = s_buyOrder.copy()
                    s_buyExecution = pd.concat(
                        [s_buyExecution.fillna(0), df_buyVolume.ix[d]],
                        axis=1).min(axis=1)
                    cashAvail = cashAvail - (s_buyExecution.abs(
                    ) * df_executePrice.ix[d]).sum() * (1 + buyCommission)
                    df_execution.ix[d] += s_buyExecution
                    df_holdings.ix[d] += s_buyExecution
            df_holdingCash.ix[d] = cashAvail
            df_turnoverPct.ix[d] < -(df_execution.ix[d].abs() *
                                     df_executePrice.ix[d]).sum() / totalValue

            if i < (len(rebDates) - 1):
                nextd = rebDates[i + 1]
            else:
                nextd = tradeDates[-1]
            ls_adjustedHoldings = fillHolding(d, nextd, tradeDates,
                                              df_holdings, df_holdingCash,
                                              df_totalReturnFactor)
            df_holdings = ls_adjustedHoldings['holdings']
            df_holdingCash = ls_adjustedHoldings['holdingCash']

    df_portfolioValue.ix[:, 0] = (df_holdings *
                                  df_markToMarketPrice.ix[tradeDates]).sum(
                                      axis=1) + df_holdingCash.ix[:, 0]
    df_weights = (df_holdings * df_markToMarketPrice.ix[tradeDates]).div(
        df_portfolioValue.ix[:, 0], axis=0)
    df_cumRets = df_portfolioValue / initHldValue - 1
    df_singlePeriodRets = df_portfolioValue / df_portfolioValue.shift(1) - 1
    df_singlePeriodRets.ix[0,
                           0] = df_portfolioValue.ix[0, 0] / initHldValue - 1

    result = {}
    result[gsConst.Const.Holding] = pd.concat(
        [df_holdings.replace(0, NA), df_holdingCash], axis=1)
    result[gsConst.Const.PortfolioValue] = df_portfolioValue
    result[gsConst.Const.Weights] = df_weights.replace(0, NA)
    result[gsConst.Const.SinglePeriodReturn] = df_singlePeriodRets
    result[gsConst.Const.CumulativeReturn] = df_cumRets
    result[gsConst.Const.Turnover] = df_turnoverPct
    print(df_cumRets.ix[-1])
    return result
コード例 #4
0
def SIMPLE_SIMULATE_DAILY_TRADE_CHN_STK(dt_begin, dt_end, initial_holding_position, \
                                        df_w_target_portfolio_weight, df_w_market_price, \
                                        df_w_total_return_factor, df_w_execute_price, \
                                        df_w_execute_price_return, df_w_trade_volume, \
                                        dict_trading_param, additionalTs):
    """股票模拟交易
    input:
        dt_begin, 开始交易日期,在rebalance之前,repeat initial holding,
                                    在rebalance之后,从begin date开始交易。
        dt_end, 结束日期
        initial_holding_position, 输入持仓,可能为一个dataframe, 也有可能是一个数量cash
        df_w_target_portfolio_weight, 目标持仓权重,每行总和应等于1
        df_w_market_price, 股票价格
        df_w_total_return_factor, 复权因子计算
        df_w_execute_price, 交易股票执行价格
        df_w_execute_price_return, 每只股票交易日的回报
        df_w_trade_volume, 每只股票交易日的交易量
        dict_trading_param, 交易参数
        additionalTs,月平衡策略参数
    output:
        result, 字典
            result['HOLDING'], 所有股票持仓和现金数据 OTV	all dates
            result['PORTFOLIO_VALUE'], 组合总价值 TV	monthly
            result['SINGLE_PERIOD_RETURN'], 组合每日回报 TV	all dates
            result['WEIGHTS'],组合中各项权重 OTV	all dates
            result['CUMULATIVE_RETURN'],累积收益 TV	all dates
            result['TURNOVER'],换手率 TV	monthly

    """
    
    df_w_target_portfolio_weight = df_w_target_portfolio_weight.asMatrix()
    df_w_market_price = df_w_market_price.asMatrix()
    df_w_total_return_factor = df_w_total_return_factor.asMatrix()
    df_w_execute_price = df_w_execute_price.asMatrix()
    df_w_execute_price_return = df_w_execute_price_return.asMatrix()
    df_w_trade_volume = df_w_trade_volume.asMatrix()

    ls_all_dates = df_w_market_price.index.intersection(df_w_total_return_factor.index.intersection(df_w_execute_price.index.intersection(df_w_execute_price_return.index.intersection(df_w_trade_volume.index))))

    ls_cashGid = gsUtils.getCashGid()

    if len(df_w_target_portfolio_weight) > 0:
        df_w_target_portfolio_weight = df_w_target_portfolio_weight.ix[ls_all_dates]
        df_w_target_portfolio_weight = df_w_target_portfolio_weight.dropna(how='all')
        ls_rebalance_dates = df_w_target_portfolio_weight.index.tolist()
        if len(ls_rebalance_dates) > 0 and gsUtils.getParm(dict_trading_param, 'execDelayPeriods', 0) > 0:
            ls_rebalance_dates = ls_rebalance_dates.shift(gsUtils.getParm(dict_trading_param, 'execDelayPeriods', 0))
            ls_rebalance_dates = gsUtils.alignDate(ls_all_dates, ls_rebalance_dates)
            df_w_target_portfolio_weight = df_w_target_portfolio_weight.ix[ls_rebalance_dates]

    ls_holding_symbols = []
    if isinstance(initial_holding_position, pd.DataFrame):
        dt_begin = initial_holding_position.index[-1]
        ls_holding_symbols = sorted(list(set([i for i in initial_holding_position.columns if i not in ls_cashGid])))
    else:
        if len(df_w_target_portfolio_weight) > 0 and gsUtils.getParm(dict_trading_param, 'shiftBeginDateToSignal', 0) > 0:
            dt_begin = max(dt_begin, df_w_target_portfolio_weight.index[0])
    ls_trade_dates = [date for date in ls_all_dates if date >= dt_begin and date <= dt_end]
    dt_begin = ls_trade_dates[0]
    dt_end = ls_trade_dates[-1]
    ls_rebalance_dates = [date for date in ls_rebalance_dates if date>=dt_begin and date<=dt_end]
    if (dt_begin > dt_end):
        raise ValueError('input error! Begin date must be less than end date!')

    ls_all_symbols = sorted(list(set.intersection(set(df_w_market_price.columns),set(df_w_execute_price.columns),set(df_w_execute_price_return.columns),set(df_w_trade_volume.columns))))
    df_w_tmp_target_portfolio_weight = df_w_target_portfolio_weight.dropna(how='all',axis=1)
    df_w_tmp_target_portfolio_weight = df_w_tmp_target_portfolio_weight.loc[:,(df_w_tmp_target_portfolio_weight!=0).any(axis=0)]
    ls_portfolio_symbols = [s for s in df_w_tmp_target_portfolio_weight.columns if s not in ls_cashGid]

    if len([s for s in ls_holding_symbols if s not in ls_all_symbols]) > 0:
        raise ValueError('input error! Initial Portfolio has non A-share stocks!')

    if len([s for s in ls_portfolio_symbols if s not in ls_all_symbols]) > 0:
        raise ValueError('input error! Target Portfolio has non A-share stocks!')


    # todo: process holding symbols
    ls_all_symbols = sorted([s for s in set.intersection(set(ls_all_symbols),set(ls_portfolio_symbols)) if s not in ls_cashGid])
    ls_price_dates = [d for d in ls_all_dates if d >= (dt_begin-pd.Timedelta('20 days')) and d <= dt_end]
    df_w_market_price = df_w_market_price.loc[ls_price_dates][ls_all_symbols]
    df_w_total_return_factor = add_missing_columns(df_w_total_return_factor, ls_all_symbols, 1).loc[ls_price_dates, ls_all_symbols]
    df_w_execute_price = df_w_execute_price.loc[ls_price_dates][ls_all_symbols]
    df_w_execute_price_return = df_w_execute_price_return.loc[ls_price_dates][ls_all_symbols]
    df_w_trade_volume = df_w_trade_volume.loc[ls_price_dates][ls_all_symbols]
    df_w_initial_holding = initial_holding_position

    if not isinstance(initial_holding_position, pd.DataFrame):
        df_w_initial_holding = pd.DataFrame(initial_holding_position, index=[dt_begin], columns=[ls_cashGid])

    # todo: if initial holding is dataframe, fill
    df_w_initial_holding = add_missing_columns(df_w_initial_holding, ls_all_symbols)
    df_w_initial_holding_cash = df_w_initial_holding.loc[df_w_initial_holding.index, ls_cashGid]
    # todo, pop godgid
    df_w_initial_holding =df_w_initial_holding.drop(ls_cashGid, axis=1)
    num_initial_holding_positionValue = float((df_w_initial_holding*df_w_market_price.ix[df_w_initial_holding.index]).sum(1)+df_w_initial_holding_cash.values[-1])
    ls_all_symbols.append(ls_cashGid)
    df_w_target_portfolio_weight_fill = add_missing_columns(df_w_target_portfolio_weight, ls_all_symbols)
    df_w_target_portfolio_weight = df_w_target_portfolio_weight_fill.ix[ls_rebalance_dates].fillna(0)
    ls_all_symbols.pop(-1)
    if (df_w_target_portfolio_weight < 0).any().any():
        raise ValueError('input error! Do not support stock short selling and cash borrowing.')

    df_w_initial_holding_cash_weight = df_w_target_portfolio_weight[ls_cashGid]
    df_w_target_portfolio_weight = df_w_target_portfolio_weight.drop(ls_cashGid, axis=1)
    df_w_initial_holding_cash_weight = 1. - df_w_target_portfolio_weight.sum(axis=1)

    df_w_buy_volume = df_w_trade_volume.copy().fillna(0)
    df_w_sell_volumn = df_w_trade_volume.copy().fillna(0)

    num_lot_size = gsUtils.getParm(dict_trading_param, 'lotSize', 0)
    df_w_buy_volume = round_to_lot(df_w_buy_volume, num_lot_size)
    df_w_sell_volumn = round_to_lot(df_w_sell_volumn, num_lot_size)

    try:
        can_trade_on_suspend = gsUtils.getParm(dict_trading_param, 'canTradeOnSuspend', 0)
        if not can_trade_on_suspend is None:
            pass
    except KeyError:
        print("no trade on suspend information")
    else:
        if can_trade_on_suspend > 0:
            df_w_buy_volume[df_w_buy_volume < 1] = np.inf
            df_w_sell_volumn[df_w_sell_volumn < 1] = np.inf

    try:
        rise_limit_thres = gsUtils.getParm(dict_trading_param, 'riseLimitThres', 0)
        if not rise_limit_thres is None:
            pass
    except KeyError:
        print("no rise limit threshold information")
    else:
        if rise_limit_thres > 0:
            rise_limit = df_w_execute_price_return > rise_limit_thres
            df_w_buy_volume[rise_limit] = 0
            df_w_sell_volumn[rise_limit & (df_w_sell_volumn > 0)] = np.inf

    try:
        fall_limit_thres = gsUtils.getParm(dict_trading_param, 'fallLimitThres', 0)
        if not fall_limit_thres is None:
            pass
    except KeyError:
        print("no fall limit threshold information")
    else:
        if fall_limit_thres < 0:
            fall_limit = df_w_execute_price_return < fall_limit_thres
            df_w_buy_volume[fall_limit & (df_w_buy_volume > 0)] = np.inf
            df_w_sell_volumn[fall_limit] = 0

    try:
        volume_limit_pct = gsUtils.getParm(dict_trading_param, 'volumeLimitPct', 0)
        if volume_limit_pct is None:
            pass
    except KeyError:
        print("no fall limit threshold information")
    else:
        if volume_limit_pct > 0:
            df_w_buy_volume = df_w_buy_volume * volume_limit_pct
            df_w_sell_volumn = df_w_sell_volumn * volume_limit_pct
        else:
            df_w_buy_volume[df_w_buy_volume > 0] = np.inf
            df_w_sell_volumn[df_w_sell_volumn > 0] = np.inf


    num_buy_commission = gsUtils.getParm(dict_trading_param, 'buyCommission', 0)
    num_sell_commission = gsUtils.getParm(dict_trading_param, 'sellCommission', 0)

    df_w_holding = pd.DataFrame(0., index=ls_trade_dates, columns=ls_all_symbols)
    df_w_weights = df_w_holding.copy()
    df_w_execution = df_w_holding.copy()
    df_w_holding_cash = pd.DataFrame(0.,index=ls_trade_dates,columns=[ls_cashGid])
    ls_getGodGid = gsUtils.getGodGid()
    df_portfolio_value = pd.DataFrame(0., index=ls_trade_dates, columns=[ls_getGodGid])

    df_w_single_period_ret = df_portfolio_value.copy()
    df_w_turnover_percent = df_portfolio_value.copy()
    
    ## trading
    d = ls_trade_dates[0]
    df_w_holding.ix[d] = df_w_initial_holding.loc[d].tolist()
    df_w_holding_cash.ix[d] = df_w_initial_holding_cash.values[-1]


    if len(ls_rebalance_dates) < 1:
        nextd = ls_trade_dates[-1]
        df_w_holding, df_w_holding_cash = fill_holding(d, nextd, ls_trade_dates, \
                                                     df_w_holding, df_w_holding_cash, \
                                                     df_w_total_return_factor)
    else:
        nextd = ls_rebalance_dates[0]
        df_w_holding, df_w_holding_cash=fill_holding(d, nextd, ls_trade_dates, \
                                                   df_w_holding, df_w_holding_cash, \
                                                   df_w_total_return_factor)

        for i in range(len(ls_rebalance_dates)):
            d = ls_rebalance_dates[i]
            df_w_current_holding_value = df_w_holding.ix[d]*(df_w_execute_price.ix[d].fillna(0)) # one line
            num_totalValue = df_w_current_holding_value.sum() + df_w_holding_cash.ix[d].values[-1]

            df_w_current_holding_weight = df_w_current_holding_value / num_totalValue
            df_w_currrent_holding_cash_weight = 1. - df_w_current_holding_weight.sum()
            df_w_target_holding_weight = df_w_target_portfolio_weight.ix[d]
            num_target_holding_cash_weight = 1. - df_w_target_holding_weight.sum()
            df_w_order_weight = df_w_target_holding_weight - df_w_current_holding_weight

            df_w_sell_order_weight = df_w_order_weight.copy()
            df_w_sell_order_weight[df_w_order_weight >= 0.0] = 0.0

            df_w_buy_order_weight = df_w_order_weight.copy()
            df_w_buy_order_weight[df_w_order_weight <= 0.0] = 0.0

            num_cash_available = df_w_holding_cash.ix[d].values[-1]
            # sell
            if (df_w_sell_order_weight.dropna() < 0.0).any():
                df_w_current_holding_weight_for_sell = df_w_current_holding_weight.copy().fillna(0)
                df_w_current_holding_weight_for_sell[df_w_current_holding_weight_for_sell <= 0.0] = 1.0
                tmp_1 = df_w_sell_order_weight / df_w_current_holding_weight_for_sell * df_w_holding.ix[d]
                df_w_sell_order = round_to_lot(tmp_1, num_lot_size) # share

                # sell all if target holding weight is equal to 0
                df_w_sell_order[df_w_target_holding_weight <= 0.0] = -df_w_holding.ix[d]

                df_w_sell_execution = df_w_sell_order.copy()
                df_w_sell_execution = -pd.concat([df_w_sell_execution.fillna(0).abs(), \
                                                 df_w_sell_volumn.ix[d]], axis=1).min(axis=1)
                num_cash_available = num_cash_available + (df_w_sell_execution.abs() * \
                                               df_w_execute_price.ix[d]).sum() * (1. - num_sell_commission)
                df_w_execution.ix[d] = df_w_execution.ix[d] + df_w_sell_execution
                df_w_holding.ix[d] = df_w_holding.ix[d] + df_w_sell_execution
            # buy
            if (df_w_buy_order_weight > 0.0).any():
                num_can_buy_weight = num_cash_available / num_totalValue - num_target_holding_cash_weight
                if num_can_buy_weight > 0:
                    num_pct = min(num_can_buy_weight / df_w_buy_order_weight.sum(), 1)
                    tmp_2 = (num_pct * df_w_buy_order_weight * num_totalValue / (1.+num_buy_commission) / df_w_execute_price.ix[d]).fillna(0)
                    df_w_buy_order = round_to_lot(tmp_2, num_lot_size)
                    df_w_buy_order = df_w_buy_order.fillna(0)
                    df_w_buy_execution = df_w_buy_order.copy() # redundant
                    df_w_buy_execution = pd.concat([df_w_buy_execution.fillna(0), \
                                                   df_w_buy_volume.ix[d]],axis=1).min(axis=1)
                    num_cash_available = num_cash_available - (abs(df_w_buy_execution) * \
                                                     df_w_execute_price.ix[d]).sum() * \
                                                     (1.+num_buy_commission)
                    df_w_execution.ix[d] = df_w_execution.ix[d] + df_w_buy_execution
                    df_w_holding.ix[d] = df_w_holding.ix[d] + df_w_buy_execution


            df_w_holding_cash.ix[d] = num_cash_available
            df_w_turnover_percent.ix[d] = (abs(df_w_execution.ix[d])*df_w_execute_price.ix[d]).sum() / num_totalValue

            if i < (len(ls_rebalance_dates) - 1):
                nextd = ls_rebalance_dates[i+1]
                df_w_holding, df_w_holding_cash = fill_holding(d, nextd, ls_trade_dates, \
                                                             df_w_holding, df_w_holding_cash, \
                                                             df_w_total_return_factor)
        # loop to the next day.
        nextd = ls_trade_dates[-1]
        df_w_holding, df_w_holding_cash = fill_holding(d, nextd, ls_trade_dates, \
                                                     df_w_holding, df_w_holding_cash, \
                                                     df_w_total_return_factor)

    df_w_portfolio_stat = pd.DataFrame(columns=[ls_getGodGid])
    df_w_portfolio_stat['value'] = (df_w_holding*df_w_market_price.ix[ls_trade_dates]).sum(axis=1)
    df_w_portfolio_stat['cash'] = df_w_holding_cash
    df_portfolio_value = df_w_portfolio_stat.sum(axis=1)
    df_w_weights = (df_w_holding*df_w_market_price.ix[ls_trade_dates]).div(df_portfolio_value,axis=0)
    df_w_single_period_ret = df_portfolio_value / df_portfolio_value.shift(1) - 1.0
    df_w_single_period_ret[0] = df_portfolio_value[0] / num_initial_holding_positionValue - 1.0
#    df_w_single_period_ret.name = ls_getGodGid
    s_cum_rets = df_portfolio_value / num_initial_holding_positionValue
    s_cum_rets[-1] = df_portfolio_value[-1] / num_initial_holding_positionValue
    print(s_cum_rets[-1])

    result = {}
    result['HOLDING'] = pd.concat([df_w_holding, df_w_holding_cash], axis=1)
    result['PORTFOLIO_VALUE'] = pd.DataFrame(df_portfolio_value, columns=[ls_getGodGid])
#    result['PORTFOLIO_VALUE'] = result['PORTFOLIO_VALUE'].reset_index()
    result['SINGLE_PERIOD_RETURN'] = pd.DataFrame(df_w_single_period_ret, columns=[ls_getGodGid])
#    result['SINGLE_PERIOD_RETURN'] = result['SINGLE_PERIOD_RETURN']
    result['WEIGHTS'] = df_w_weights
    result['CUMULATIVE_RETURN'] = pd.DataFrame(s_cum_rets, columns=[ls_getGodGid])
    result['TURNOVER'] = pd.DataFrame(df_w_turnover_percent, columns=[ls_getGodGid])
    return result
コード例 #5
0
ファイル: main.py プロジェクト: leolle/simulate
    if dict_trading_param['volumeLimitPct'] > 0:
        df_w_buy_volume = df_w_buy_volume * dict_trading_param['volumeLimitPct']
        df_w_sell_volumn = df_w_sell_volumn * dict_trading_param['volumeLimitPct']
    else:
        df_w_buy_volume[df_w_buy_volume > 0] = np.inf
        df_w_sell_volumn[df_w_sell_volumn > 0] = np.inf


num_buy_commission = get_param(dict_trading_param, 'buyCommission', 0)
num_sell_commission = get_param(dict_trading_param, 'sellCommission', 0)

df_w_holding = pd.DataFrame(0., index=ls_trade_dates, columns=ls_all_symbols)
df_w_weights = df_w_holding.copy()
df_w_execution = df_w_holding.copy()
df_w_holding_cash = pd.DataFrame(0.,index=ls_trade_dates,columns=[ls_cashGid])
ls_getGodGid = gsUtils.getGodGid()
df_portfolio_value = pd.DataFrame(0., index=ls_trade_dates, columns=[ls_getGodGid])

df_w_single_period_return = df_portfolio_value.copy()
df_w_turnover_percent = df_portfolio_value.copy()

## trading
d = ls_trade_dates[0]
df_w_holding.ix[d] = df_w_initial_holding.loc[d].tolist()
df_w_holding_cash.ix[d] = df_w_initial_holdingCash.values[-1][-1]


if len(ls_rebalance_dates) < 1:
    nextd = ls_trade_dates[-1]
    df_w_holding, df_w_holding_cash = fill_holding(d, nextd, ls_trade_dates, \
                                                 df_w_holding, df_w_holding_cash, \