microsoft / qlib

Qlib is an AI-oriented quantitative investment platform that aims to realize the potential, empower research, and create value using AI technologies in quantitative investment, from exploring ideas to implementing productions. Qlib supports diverse machine learning modeling paradigms. including supervised learning, market dynamics modeling, and RL.
https://qlib.readthedocs.io/en/latest/
MIT License
15.18k stars 2.6k forks source link

How to do portfolio simulation and backtest with the original stock prices instead of the adjusted ones #1833

Open tonduy opened 1 month ago

tonduy commented 1 month ago

Dear Qlib Team,

Thank you very much for providing this great framework!

I understand based on the documentation that the prices of the stocks are adjusted and the original price can be get via $close / $factor.

But now I wanted to ask if it is possible to run the whole portfolio simulation and backtest with the original prices instead of the adjusted ones so that the amount of stocks to buy also represents a real life scenario.

I would highly appreciate an answer of you. I tried to modify the exchange.py file to return for the deal price the original one, but this messes with the whole backtesting:

def get_deal_price(
        self,
        stock_id: str,
        start_time: pd.Timestamp,
        end_time: pd.Timestamp,
        direction: OrderDir,
        method: Optional[str] = "ts_data_last",
    ) -> Union[None, int, float, bool, IndexData]:
        if direction == OrderDir.SELL:
            pstr = self.sell_price
        elif direction == OrderDir.BUY:
            pstr = self.buy_price
        else:
            raise NotImplementedError(f"This type of input is not supported")
        deal_price = self.quote.get_data(stock_id, start_time, end_time, field=pstr, method=method)
        if method is not None and (deal_price is None or np.isnan(deal_price) or deal_price <= 1e-08):
            self.logger.warning(f"(stock_id:{stock_id}, trade_time:{(start_time, end_time)}, {pstr}): {deal_price}!!!")
            self.logger.warning(f"setting deal_price to close price")
            deal_price = self.get_close(stock_id, start_time, end_time, method)
        factor = self.get_factor(stock_id, start_time, end_time)
        original_price = deal_price / factor
        return original_price
SunsetWolf commented 1 month ago

The data used by qlib are all post-weighted, why do you use post-weighted data? Post-weighting ensures that the historical price remains constant and adjusts the current stock price after each equity event. How to post weight? The reason for using the post-weighting factor is so that all stocks are at 1 on the first trading day of the calculation, and subsequent data is added or subtracted from 1 for easy comparison. If the original price is used to replace the post-weighting price, the price difference of thousands of times will make the model calculation very difficult.