Exemple #1
0
    def check_nv(self):
        # check whether first/last period is missing
        ps = self.fund.price_series
        if (~ps[ps.index[ps.index <= self._first_month_end]].notnull()).all() \
                or (~ps[ps.index[ps.index >= self._last_month_start]].notnull()).all():
            raise DataError("First/Last-period NV Missing")

        # check whether all return equals 0
        if (self.fund.return_series.dropna() == 0).all():
            raise DataError("All return equal to Zero")

        min_lengths = {
            "w": {
                "style": 12,
                "industry": 24
            },
            "d": {
                "style": 12,
                "industry": 24
            }
        }
        n = len(self.fund.price_series.dropna())
        if n < min_lengths[self.freq][self.factor_type]:
            raise DataError("Data Missing Too much, only got {n}".format(n=n))

        return True
Exemple #2
0
    def check_before_pre(self):
        # Check Foundation Date(or First Nv Date)
        if self.portfolio.foundation_date is not None:
            if self.date - relativedelta(months=6) < self.portfolio.foundation_date:
                raise DataError(
                    "Founded less than 6 months: foundation_date: {fd}, statistic_date: {sd}".format(
                        fd=self.portfolio.foundation_date, sd=self.date))
        else:
            raise DataError("Missing Foundation Date / First Nv Date")

        if len(self.portfolio.return_series.dropna()) < 12:
            raise DataError("Valid Sample less than 12")
Exemple #3
0
    def check_totalnv_len(self):
        min_lengths = {"w": {"style": 24, "industry": 52}, "d": {"style": 24, "industry": 52}}
        n = len(self.fund.price_series_whole.dropna())
        N = min_lengths[self.freq][self.factor_type]
        if n < N:
            raise DataError("Total NV length doesn't satisfy, {n}/{N}".format(n=n, N=N))

        return True
Exemple #4
0
    def load_type(self):
        sql = "SELECT stype_code FROM base.fund_type_mapping " \
              "WHERE fund_id = '{fid}' AND typestandard_code = '601' AND type_code <> '60109' " \
              "AND flag = 1 AND stype_code IS NOT NULL".format(fid=self.fund_id)
        tp = self.engine.execute(sql).fetchone()

        if tp is None:
            raise DataError("Fund {fid} does not have a classification".format(fid=self.fund_id))

        return tp[0]
Exemple #5
0
    def data(self):
        self.check_before_pre()
        x_data = self.factors.data.rename(columns=self.factor_names).fillna(method="ffill").dropna()
        y_data = (self.portfolio.return_series.fillna(method="ffill")
                  - self.benchmark_rf.return_series.fillna(method="ffill")).dropna()
        x_data, y_data = [_ for _ in x_data.align(y_data, axis=0, join="inner")]

        if len(x_data) < 12:
            raise DataError("Valid Sample less than 12 after align ")

        return x_data, y_data
Exemple #6
0
    def __init__(self,
                 fund_id: str,
                 start: dt.date,
                 end: dt.date,
                 freq: str,
                 factor_type: str,
                 ftypes=None,
                 **kwargs):
        """

        Args:
            fund_id: str
            start: datetime.date, or None
            end: datetime.date
            freq: str, optional {"w", "m"}
            factor_type: str, optional {"style", "industry"}
            ftypes: dict, or None

            **kwargs:
                arguments for `scipy.optimize.minize` function, including

                tol: float, default 1e-18

                options: dict, default None
        """

        self.start, self.end = start, end
        self.factor_type = factor_type
        self.freq = freq
        if self.start is None:
            if self.factor_type == "style":
                self.start = self.end - relativedelta(months=6)
            elif self.factor_type == "industry":
                self.start = self.end - relativedelta(years=1)
            self.start = dt.date(
                self.start.year, self.start.month,
                cld.monthrange(self.start.year,
                               self.start.month)[1]) + dt.timedelta(1)

        self.fund = Portfolio(fund_id, self.start, self.end, self.freq)
        self.sampler = Sampler(self.fund, self.freq, factor_type)
        if not self.sampler.pass_check():
            raise DataError("do not pass check")

        if ftypes is None:
            print("ftypes not set, automatically selecting...")
            # 股票型
            if self.fund.stype in {"020101"}:
                if self.factor_type == "style":
                    ftypes = FactorUsed.STOCK
                elif self.factor_type == "industry":
                    ftypes = FactorUsed.SWS_28

            # 纯债型, 混合债券型
            elif self.fund.stype in {"020201", "020202"}:
                if self.factor_type == "style":
                    ftypes = FactorUsed.BOND

            # 混合策略
            elif self.fund.stype in {
                    "020301", "020302", "020303", "020304", "020305"
            }:
                if self.factor_type == "style":
                    ftypes = FactorUsed.BLEND

        if ftypes is None:
            raise DataError("Unsupported fund type for {} sharpe model".format(
                self.factor_type))

        self.factors = Factors(ftypes, self.start, self.end, freq)
        SharpeFactor.__init__(self, self.fund, self.factors, **kwargs)

        self.factor_type = factor_type
Exemple #7
0
    def _init_cons_by_stype(self):
        # 股票型
        if self.stype in {"020101"}:
            self._cons.extend([
                {
                    "type":
                    "ineq",
                    "fun":
                    lambda x: sum(x[self.tf[FactorClassification.STOCK_CODE]])
                    - 0.8
                },
                {
                    "type":
                    "ineq",
                    "fun":
                    lambda x: sum(x[self.tf[FactorClassification.CASH_CODE]]) -
                    0
                },
            ])

        # 债券策略
        elif self.stype in {"020201", "020202"}:
            self._cons.extend([
                {
                    "type":
                    "ineq",
                    "fun":
                    lambda x: sum(x[self.tf[FactorClassification.BOND_CODE]]) -
                    0.8
                },
                {
                    "type":
                    "ineq",
                    "fun":
                    lambda x: sum(x[self.tf[FactorClassification.CASH_CODE]]) -
                    0
                },
            ])

        # 混合策略
        elif self.stype in {"020301", "020302", "020303", "020304", "020305"}:
            self._cons.extend([
                {
                    "type":
                    "ineq",
                    "fun":
                    lambda x: 0.8 - sum(x[self.tf[FactorClassification.
                                                  STOCK_CODE]])
                },
                {
                    "type":
                    "ineq",
                    "fun":
                    lambda x: 0.8 - sum(x[self.tf[FactorClassification.
                                                  BOND_CODE]])
                },
                {
                    "type":
                    "ineq",
                    "fun":
                    lambda x: sum(x[self.tf[FactorClassification.CASH_CODE]]) -
                    0
                },
            ])
        else:
            raise DataError("No supported fund type")