1
0
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:
Young
2021-07-04 06:41:34 +00:00
parent 2b4a493617
commit 7048bef7c6
4 changed files with 57 additions and 12 deletions

View File

@@ -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)

View File

@@ -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,

View File

@@ -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):

View File

@@ -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"))