1
0
mirror of https://github.com/microsoft/qlib.git synced 2026-07-12 07:16:54 +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 .position import BasePosition, InfPosition, Position
from .report import Report, Indicator from .report import Report, Indicator
from .order import Order from .order import BaseTradeDecision, Order
from .exchange import Exchange from .exchange import Exchange
""" """
@@ -226,6 +226,7 @@ class Account:
trade_end_time: pd.Timestamp, trade_end_time: pd.Timestamp,
trade_exchange: Exchange, trade_exchange: Exchange,
atomic: bool, atomic: bool,
outer_trade_decision: BaseTradeDecision,
generate_report: bool = False, generate_report: bool = False,
trade_info: list = None, trade_info: list = None,
inner_order_indicators: Indicator = None, inner_order_indicators: Indicator = None,
@@ -276,7 +277,9 @@ class Account:
if atomic: if atomic:
self.indicator.update_order_indicators(trade_start_time, trade_end_time, trade_info, trade_exchange) self.indicator.update_order_indicators(trade_start_time, trade_end_time, trade_info, trade_exchange)
else: 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.cal_trade_indicators(trade_start_time, self.freq, indicator_config)
self.indicator.record(trade_start_time) self.indicator.record(trade_start_time)

View File

@@ -299,6 +299,7 @@ class NestedExecutor(BaseExecutor):
trade_end_time, trade_end_time,
self.trade_exchange, self.trade_exchange,
atomic=False, atomic=False,
outer_trade_decision=trade_decision,
generate_report=self.generate_report, generate_report=self.generate_report,
inner_order_indicators=inner_order_indicators, inner_order_indicators=inner_order_indicators,
indicator_config=self.indicator_config, indicator_config=self.indicator_config,
@@ -409,6 +410,7 @@ class SimulatorExecutor(BaseExecutor):
trade_end_time, trade_end_time,
self.trade_exchange, self.trade_exchange,
atomic=True, atomic=True,
outer_trade_decision=trade_decision,
generate_report=self.generate_report, generate_report=self.generate_report,
trade_info=execute_result, trade_info=execute_result,
indicator_config=self.indicator_config, indicator_config=self.indicator_config,

View File

@@ -40,7 +40,7 @@ class Order:
""" """
stock_id: str 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) # The interval of the order which belongs to (NOTE: this is not the expected order dealing range time)
start_time: pd.Timestamp start_time: pd.Timestamp
@@ -48,7 +48,7 @@ class Order:
direction: int direction: int
factor: float factor: float
deal_amount: Optional[float] = None deal_amount: Optional[float] = None # `deal_amount` is a non-negative value
# FIXME: # FIXME:
# for compatible now. # for compatible now.
@@ -62,6 +62,33 @@ class Order:
raise NotImplementedError("direction not supported, `Order.SELL` for sell, `Order.BUY` for buy") raise NotImplementedError("direction not supported, `Order.SELL` for sell, `Order.BUY` for buy")
self.deal_amount = 0 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 @staticmethod
def parse_dir(direction: Union[str, int, np.integer, OrderDir]) -> OrderDir: def parse_dir(direction: Union[str, int, np.integer, OrderDir]) -> OrderDir:
if isinstance(direction, OrderDir): if isinstance(direction, OrderDir):

View File

@@ -4,6 +4,8 @@
from collections import OrderedDict from collections import OrderedDict
from logging import warning from logging import warning
from typing import List
from qlib.backtest.order import BaseTradeDecision, Order
import pandas as pd import pandas as pd
import pathlib import pathlib
import warnings import warnings
@@ -241,13 +243,13 @@ class Indicator:
trade_cost = dict() trade_cost = dict()
for order, _trade_val, _trade_cost, _trade_price in trade_info: for order, _trade_val, _trade_cost, _trade_price in trade_info:
amount[order.stock_id] = order.amount * (order.direction * 2 - 1) amount[order.stock_id] = order.amount_delta
deal_amount[order.stock_id] = order.deal_amount * (order.direction * 2 - 1) deal_amount[order.stock_id] = order.deal_amount_delta
trade_price[order.stock_id] = _trade_price 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 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["deal_amount"] = pd.Series(deal_amount)
self.order_indicator["trade_price"] = pd.Series(trade_price) self.order_indicator["trade_price"] = pd.Series(trade_price)
self.order_indicator["trade_value"] = pd.Series(trade_value) self.order_indicator["trade_value"] = pd.Series(trade_value)
@@ -271,13 +273,13 @@ class Indicator:
) / self.order_indicator["base_price"] ) / self.order_indicator["base_price"]
def _agg_order_trade_info(self, inner_order_indicators): def _agg_order_trade_info(self, inner_order_indicators):
amount = pd.Series() inner_amount = pd.Series()
deal_amount = pd.Series() deal_amount = pd.Series()
trade_price = pd.Series() trade_price = pd.Series()
trade_value = pd.Series() trade_value = pd.Series()
trade_cost = pd.Series() trade_cost = pd.Series()
for _order_indicator in inner_order_indicators: 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) deal_amount = deal_amount.add(_order_indicator["deal_amount"], fill_value=0)
trade_price = trade_price.add( trade_price = trade_price.add(
_order_indicator["trade_price"] * _order_indicator["deal_amount"], fill_value=0 _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_value = trade_value.add(_order_indicator["trade_value"], fill_value=0)
trade_cost = trade_cost.add(_order_indicator["trade_cost"], 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 self.order_indicator["deal_amount"] = deal_amount
trade_price /= self.order_indicator["deal_amount"] trade_price /= self.order_indicator["deal_amount"]
self.order_indicator["trade_price"] = trade_price self.order_indicator["trade_price"] = trade_price
self.order_indicator["trade_value"] = trade_value self.order_indicator["trade_value"] = trade_value
self.order_indicator["trade_cost"] = trade_cost 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): def _agg_order_fulfill_rate(self):
self.order_indicator["ffr"] = self.order_indicator["deal_amount"] / self.order_indicator["amount"] 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_fulfill_rate()
self._update_order_price_advantage(trade_exchange, trade_start_time, trade_end_time) 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._agg_order_trade_info(inner_order_indicators)
self._update_trade_amount(outer_trade_decision)
self._agg_order_fulfill_rate() self._agg_order_fulfill_rate()
pa_config = indicator_config.get("pa_config", {}) pa_config = indicator_config.get("pa_config", {})
self._agg_order_price_advantage(inner_order_indicators, base_price=pa_config.get("base_price", "twap")) self._agg_order_price_advantage(inner_order_indicators, base_price=pa_config.get("base_price", "twap"))