mirror of
https://github.com/microsoft/qlib.git
synced 2026-07-01 10:01:19 +08:00
fix ffr and order amount
This commit is contained in:
@@ -9,7 +9,7 @@ import pandas as pd
|
||||
|
||||
from .position import BasePosition, InfPosition, Position
|
||||
from .report import Report, Indicator
|
||||
from .order import Order
|
||||
from .order import BaseTradeDecision, Order
|
||||
from .exchange import Exchange
|
||||
|
||||
"""
|
||||
@@ -226,6 +226,7 @@ class Account:
|
||||
trade_end_time: pd.Timestamp,
|
||||
trade_exchange: Exchange,
|
||||
atomic: bool,
|
||||
outer_trade_decision: BaseTradeDecision,
|
||||
generate_report: bool = False,
|
||||
trade_info: list = None,
|
||||
inner_order_indicators: Indicator = None,
|
||||
@@ -276,7 +277,9 @@ class Account:
|
||||
if atomic:
|
||||
self.indicator.update_order_indicators(trade_start_time, trade_end_time, trade_info, trade_exchange)
|
||||
else:
|
||||
self.indicator.agg_order_indicators(inner_order_indicators, indicator_config)
|
||||
self.indicator.agg_order_indicators(
|
||||
inner_order_indicators, indicator_config=indicator_config, outer_trade_decision=outer_trade_decision
|
||||
)
|
||||
|
||||
self.indicator.cal_trade_indicators(trade_start_time, self.freq, indicator_config)
|
||||
self.indicator.record(trade_start_time)
|
||||
|
||||
@@ -299,6 +299,7 @@ class NestedExecutor(BaseExecutor):
|
||||
trade_end_time,
|
||||
self.trade_exchange,
|
||||
atomic=False,
|
||||
outer_trade_decision=trade_decision,
|
||||
generate_report=self.generate_report,
|
||||
inner_order_indicators=inner_order_indicators,
|
||||
indicator_config=self.indicator_config,
|
||||
@@ -409,6 +410,7 @@ class SimulatorExecutor(BaseExecutor):
|
||||
trade_end_time,
|
||||
self.trade_exchange,
|
||||
atomic=True,
|
||||
outer_trade_decision=trade_decision,
|
||||
generate_report=self.generate_report,
|
||||
trade_info=execute_result,
|
||||
indicator_config=self.indicator_config,
|
||||
|
||||
@@ -40,7 +40,7 @@ class Order:
|
||||
"""
|
||||
|
||||
stock_id: str
|
||||
amount: float
|
||||
amount: float # `amount` is a non-negative value
|
||||
|
||||
# The interval of the order which belongs to (NOTE: this is not the expected order dealing range time)
|
||||
start_time: pd.Timestamp
|
||||
@@ -48,7 +48,7 @@ class Order:
|
||||
|
||||
direction: int
|
||||
factor: float
|
||||
deal_amount: Optional[float] = None
|
||||
deal_amount: Optional[float] = None # `deal_amount` is a non-negative value
|
||||
|
||||
# FIXME:
|
||||
# for compatible now.
|
||||
@@ -62,6 +62,33 @@ class Order:
|
||||
raise NotImplementedError("direction not supported, `Order.SELL` for sell, `Order.BUY` for buy")
|
||||
self.deal_amount = 0
|
||||
|
||||
@property
|
||||
def amount_delta(self) -> float:
|
||||
"""
|
||||
return the delta of amount.
|
||||
- Positive value indicates buying `amount` of share
|
||||
- Negative value indicates selling `amount` of share
|
||||
"""
|
||||
return self.amount * self.sign
|
||||
|
||||
@property
|
||||
def deal_amount_delta(self) -> float:
|
||||
"""
|
||||
return the delta of deal_amount.
|
||||
- Positive value indicates buying `deal_amount` of share
|
||||
- Negative value indicates selling `deal_amount` of share
|
||||
"""
|
||||
return self.deal_amount * self.sign
|
||||
|
||||
@property
|
||||
def sign(self) -> float:
|
||||
"""
|
||||
return the sign of trading
|
||||
- `+1` indicates buying
|
||||
- `-1` value indicates selling
|
||||
"""
|
||||
return self.direction * 2 - 1
|
||||
|
||||
@staticmethod
|
||||
def parse_dir(direction: Union[str, int, np.integer, OrderDir]) -> OrderDir:
|
||||
if isinstance(direction, OrderDir):
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
from collections import OrderedDict
|
||||
from logging import warning
|
||||
from typing import List
|
||||
from qlib.backtest.order import BaseTradeDecision, Order
|
||||
import pandas as pd
|
||||
import pathlib
|
||||
import warnings
|
||||
@@ -241,13 +243,13 @@ class Indicator:
|
||||
trade_cost = dict()
|
||||
|
||||
for order, _trade_val, _trade_cost, _trade_price in trade_info:
|
||||
amount[order.stock_id] = order.amount * (order.direction * 2 - 1)
|
||||
deal_amount[order.stock_id] = order.deal_amount * (order.direction * 2 - 1)
|
||||
amount[order.stock_id] = order.amount_delta
|
||||
deal_amount[order.stock_id] = order.deal_amount_delta
|
||||
trade_price[order.stock_id] = _trade_price
|
||||
trade_value[order.stock_id] = _trade_val * (order.direction * 2 - 1)
|
||||
trade_value[order.stock_id] = _trade_val * order.sign
|
||||
trade_cost[order.stock_id] = _trade_cost
|
||||
|
||||
self.order_indicator["amount"] = pd.Series(amount)
|
||||
self.order_indicator["amount"] = self.order_indicator["inner_amount"] = pd.Series(amount)
|
||||
self.order_indicator["deal_amount"] = pd.Series(deal_amount)
|
||||
self.order_indicator["trade_price"] = pd.Series(trade_price)
|
||||
self.order_indicator["trade_value"] = pd.Series(trade_value)
|
||||
@@ -271,13 +273,13 @@ class Indicator:
|
||||
) / self.order_indicator["base_price"]
|
||||
|
||||
def _agg_order_trade_info(self, inner_order_indicators):
|
||||
amount = pd.Series()
|
||||
inner_amount = pd.Series()
|
||||
deal_amount = pd.Series()
|
||||
trade_price = pd.Series()
|
||||
trade_value = pd.Series()
|
||||
trade_cost = pd.Series()
|
||||
for _order_indicator in inner_order_indicators:
|
||||
amount = amount.add(_order_indicator["amount"], fill_value=0)
|
||||
inner_amount = inner_amount.add(_order_indicator["inner_amount"], fill_value=0)
|
||||
deal_amount = deal_amount.add(_order_indicator["deal_amount"], fill_value=0)
|
||||
trade_price = trade_price.add(
|
||||
_order_indicator["trade_price"] * _order_indicator["deal_amount"], fill_value=0
|
||||
@@ -285,13 +287,21 @@ class Indicator:
|
||||
trade_value = trade_value.add(_order_indicator["trade_value"], fill_value=0)
|
||||
trade_cost = trade_cost.add(_order_indicator["trade_cost"], fill_value=0)
|
||||
|
||||
self.order_indicator["amount"] = amount
|
||||
self.order_indicator["inner_amount"] = inner_amount
|
||||
self.order_indicator["deal_amount"] = deal_amount
|
||||
trade_price /= self.order_indicator["deal_amount"]
|
||||
self.order_indicator["trade_price"] = trade_price
|
||||
self.order_indicator["trade_value"] = trade_value
|
||||
self.order_indicator["trade_cost"] = trade_cost
|
||||
|
||||
def _update_trade_amount(self, outer_trade_decision: BaseTradeDecision):
|
||||
# NOTE: these indicator is designed for order execution, so the
|
||||
decision: List[Order] = outer_trade_decision.get_decision()
|
||||
if decision is None:
|
||||
self.order_indicator["amount"] = pd.Series()
|
||||
else:
|
||||
self.order_indicator["amount"] = pd.Series({order.stock_id: order.amount_delta for order in decision})
|
||||
|
||||
def _agg_order_fulfill_rate(self):
|
||||
self.order_indicator["ffr"] = self.order_indicator["deal_amount"] / self.order_indicator["amount"]
|
||||
|
||||
@@ -367,8 +377,11 @@ class Indicator:
|
||||
self._update_order_fulfill_rate()
|
||||
self._update_order_price_advantage(trade_exchange, trade_start_time, trade_end_time)
|
||||
|
||||
def agg_order_indicators(self, inner_order_indicators, indicator_config={}):
|
||||
def agg_order_indicators(
|
||||
self, inner_order_indicators, outer_trade_decision: BaseTradeDecision, indicator_config={}
|
||||
):
|
||||
self._agg_order_trade_info(inner_order_indicators)
|
||||
self._update_trade_amount(outer_trade_decision)
|
||||
self._agg_order_fulfill_rate()
|
||||
pa_config = indicator_config.get("pa_config", {})
|
||||
self._agg_order_price_advantage(inner_order_indicators, base_price=pa_config.get("base_price", "twap"))
|
||||
|
||||
Reference in New Issue
Block a user