# Path: alphaware/const.py
# INDEX_FACTOR = namedtuple('INDEX_FACTOR', ['date_index', 'sec_index', 'full_index', 'col_score'])
# 
# Path: alphaware/enums.py
# class FreqType(StrEnum):
#     EOD = 'D'
#     EOW = 'W'
#     EOM = 'M'
#     EOQ = 'Q'
#     EOSY = 'S'
#     EOY = 'Y'
# 
# class OutputDataFormat(IntEnum):
#     MULTI_INDEX_DF = 0
#     PITVOT_TABLE_DF = 1
# 
# Path: alphaware/utils/input_validation.py
# @expect_types(arg=(list, np.ndarray, pd.DataFrame, pd.Series))
# def ensure_pd_df(func, argname, arg):
#     if isinstance(arg, pd.DataFrame):
#         return arg
#     else:
#         return pd.DataFrame(arg)


import pandas as pd
import numpy as np
from argcheck import (expect_types,
                      optional,
                      preprocess)
from xutils import py_assert
from alphaware.const import INDEX_FACTOR
from alphaware.enums import (FreqType,
                             OutputDataFormat)
from .input_validation import ensure_pd_df
    elif freq == FreqType.EOY:
        return data_.groupby(pd.TimeGrouper(freq='A'))


@expect_types(x=(pd.DataFrame, pd.Series))
def quantile_calc(x, quantiles, bins):
    if quantiles is not None and bins is None:
        return pd.qcut(x, quantiles, labels=False) + 1
    elif bins is not None and quantiles is None:
        return pd.cut(x, bins, labels=False) + 1
    raise ValueError('Either quantiles or bins should be provided')


@expect_types(x=(pd.DataFrame, pd.Series))
def fwd_return(x, date_index=INDEX_FACTOR.date_index, sec_index=INDEX_FACTOR.sec_index, period=1):
    """
    每个日期和股票代码对应的未来收益
    """
    dates = sorted(set(x.index.get_level_values(date_index)))
    ret = pd.DataFrame()
    for i in range(len(dates) - period):
        shift_date = dates[i + period]
        data_concat = x.loc[shift_date].reset_index()
        data_concat[date_index] = [dates[i]] * len(data_concat)
        ret = pd.concat([ret, data_concat], axis=0)
    ret.set_index([date_index, sec_index], inplace=True)
    ret.columns = ['fwd_return']
    return ret



# Path: alphaware/const.py
# INDEX_FACTOR = namedtuple('INDEX_FACTOR', ['date_index', 'sec_index', 'full_index', 'col_score'])
# 
# Path: alphaware/enums.py
# class FreqType(StrEnum):
#     EOD = 'D'
#     EOW = 'W'
#     EOM = 'M'
#     EOQ = 'Q'
#     EOSY = 'S'
#     EOY = 'Y'
# 
# class OutputDataFormat(IntEnum):
#     MULTI_INDEX_DF = 0
#     PITVOT_TABLE_DF = 1
# 
# Path: alphaware/utils/input_validation.py
# @expect_types(arg=(list, np.ndarray, pd.DataFrame, pd.Series))
# def ensure_pd_df(func, argname, arg):
#     if isinstance(arg, pd.DataFrame):
#         return arg
#     else:
#         return pd.DataFrame(arg)


# Path: alphaware/utils/pandas_utils.py
import pandas as pd
import numpy as np
from argcheck import (expect_types,
                      optional,
                      preprocess)
from xutils import py_assert
from alphaware.const import INDEX_FACTOR
from alphaware.enums import (FreqType,
                             OutputDataFormat)
from .input_validation import ensure_pd_df

    elif freq == FreqType.EOY:
        return data_.groupby(pd.TimeGrouper(freq='A'))


@expect_types(x=(pd.DataFrame, pd.Series))
def quantile_calc(x, quantiles, bins):
    if quantiles is not None and bins is None:
        return pd.qcut(x, quantiles, labels=False) + 1
    elif bins is not None and quantiles is None:
        return pd.cut(x, bins, labels=False) + 1
    raise ValueError('Either quantiles or bins should be provided')


@expect_types(x=(pd.DataFrame, pd.Series))
def fwd_return(x, date_index=INDEX_FACTOR.date_index, sec_index=INDEX_FACTOR.sec_index, period=1):
    """
    每个日期和股票代码对应的未来收益
    """
    dates = sorted(set(x.index.get_level_values(date_index)))
    ret = pd.DataFrame()
    for i in range(len(dates) - period):
        shift_date = dates[i + period]
        data_concat = x.loc[shift_date].reset_index()
        data_concat[date_index] = [dates[i]] * len(data_concat)
        ret = pd.concat([ret, data_concat], axis=0)
    ret.set_index([date_index, sec_index], inplace=True)
    ret.columns = ['fwd_return']
    return ret



def load_factor_data_from_csv(csv_file, date_index=INDEX_FACTOR.date_index, sec_index=INDEX_FACTOR.sec_index):