mirror of
https://github.com/microsoft/qlib.git
synced 2026-07-17 17:34:35 +08:00
Merge pull request #66 from microsoft/support-non-fullfill-rate
support non-full-fill rate of executor
This commit is contained in:
@@ -49,42 +49,38 @@ class Account:
|
|||||||
return self.current.position["cash"]
|
return self.current.position["cash"]
|
||||||
|
|
||||||
def update_state_from_order(self, order, trade_val, cost, trade_price):
|
def update_state_from_order(self, order, trade_val, cost, trade_price):
|
||||||
# update cash
|
|
||||||
if order.direction == Order.SELL: # 0 for sell
|
|
||||||
self.current.position["cash"] += trade_val - cost
|
|
||||||
elif order.direction == Order.BUY: # 1 for buy
|
|
||||||
self.current.position["cash"] -= trade_val + cost
|
|
||||||
else:
|
|
||||||
raise NotImplementedError("{} ".format(order.direction))
|
|
||||||
# update turnover
|
# update turnover
|
||||||
self.to += trade_val
|
self.to += trade_val
|
||||||
# update cost
|
# update cost
|
||||||
self.ct += cost
|
self.ct += cost
|
||||||
# update return
|
# update return
|
||||||
# update self.rtn from order
|
# update self.rtn from order
|
||||||
|
trade_amount = trade_val / trade_price
|
||||||
if order.direction == Order.SELL: # 0 for sell
|
if order.direction == Order.SELL: # 0 for sell
|
||||||
# when sell stock, get profit from price change
|
# when sell stock, get profit from price change
|
||||||
profit = trade_val - self.current.get_stock_price(order.stock_id) * order.deal_amount
|
profit = trade_val - self.current.get_stock_price(order.stock_id) * trade_amount
|
||||||
self.rtn += profit # note here do not consider cost
|
self.rtn += profit # note here do not consider cost
|
||||||
elif order.direction == Order.BUY: # 1 for buy
|
elif order.direction == Order.BUY: # 1 for buy
|
||||||
# when buy stock, we get return for the rtn computing method
|
# when buy stock, we get return for the rtn computing method
|
||||||
# profit in buy order is to make self.rtn is consistent with self.earning at the end of date
|
# profit in buy order is to make self.rtn is consistent with self.earning at the end of date
|
||||||
profit = self.current.get_stock_price(order.stock_id) * order.deal_amount - trade_val
|
profit = self.current.get_stock_price(order.stock_id) * trade_amount - trade_val
|
||||||
self.rtn += profit
|
self.rtn += profit
|
||||||
|
|
||||||
def update_order(self, order, trade_val, cost, trade_price):
|
def update_order(self, order, trade_val, cost, trade_price):
|
||||||
# if stock is sold out, no stock price information in Position, then we should update account first, then update current position
|
# if stock is sold out, no stock price information in Position, then we should update account first, then update current position
|
||||||
# if stock is bought, there is no stock in current position, update current, then update account
|
# if stock is bought, there is no stock in current position, update current, then update account
|
||||||
|
# The cost will be substracted from the cash at last. So the trading logic can ignore the cost calculation
|
||||||
|
trade_amount = trade_val / trade_price
|
||||||
if order.direction == Order.SELL:
|
if order.direction == Order.SELL:
|
||||||
# sell stock
|
# sell stock
|
||||||
self.update_state_from_order(order, trade_val, cost, trade_price)
|
self.update_state_from_order(order, trade_val, cost, trade_price)
|
||||||
# update current position
|
# update current position
|
||||||
# for may sell all of stock_id
|
# for may sell all of stock_id
|
||||||
self.current.update_order(order, trade_price)
|
self.current.update_order(order, trade_val, cost, trade_price)
|
||||||
else:
|
else:
|
||||||
# buy stock
|
# buy stock
|
||||||
# deal order, then update state
|
# deal order, then update state
|
||||||
self.current.update_order(order, trade_price)
|
self.current.update_order(order, trade_val, cost, trade_price)
|
||||||
self.update_state_from_order(order, trade_val, cost, trade_price)
|
self.update_state_from_order(order, trade_val, cost, trade_price)
|
||||||
|
|
||||||
def update_daily_end(self, today, trader):
|
def update_daily_end(self, today, trader):
|
||||||
|
|||||||
@@ -208,14 +208,9 @@ class Exchange:
|
|||||||
# If the order can only be deal 0 trade_val. Nothing to be updated
|
# If the order can only be deal 0 trade_val. Nothing to be updated
|
||||||
# Otherwise, it will result some stock with 0 amount in the position
|
# Otherwise, it will result some stock with 0 amount in the position
|
||||||
if trade_account:
|
if trade_account:
|
||||||
trade_account.update_order(
|
trade_account.update_order(order=order, trade_val=trade_val, cost=trade_cost, trade_price=trade_price)
|
||||||
order=order,
|
|
||||||
trade_val=trade_val,
|
|
||||||
cost=trade_cost,
|
|
||||||
trade_price=trade_price,
|
|
||||||
)
|
|
||||||
elif position:
|
elif position:
|
||||||
position.update_order(order, trade_price)
|
position.update_order(order=order, trade_val=trade_val, cost=trade_cost, trade_price=trade_price)
|
||||||
|
|
||||||
return trade_val, trade_cost, trade_price
|
return trade_val, trade_cost, trade_price
|
||||||
|
|
||||||
|
|||||||
@@ -43,38 +43,44 @@ class Position:
|
|||||||
self.position[stock_id]["price"] = price
|
self.position[stock_id]["price"] = price
|
||||||
self.position[stock_id]["weight"] = 0 # update the weight in the end of the trade date
|
self.position[stock_id]["weight"] = 0 # update the weight in the end of the trade date
|
||||||
|
|
||||||
def buy_stock(self, stock_id, amount, price):
|
def buy_stock(self, stock_id, trade_val, cost, trade_price):
|
||||||
|
trade_amount = trade_val / trade_price
|
||||||
if stock_id not in self.position:
|
if stock_id not in self.position:
|
||||||
self.init_stock(stock_id=stock_id, amount=amount, price=price)
|
self.init_stock(stock_id=stock_id, amount=trade_amount, price=trade_price)
|
||||||
else:
|
else:
|
||||||
# exist, add amount
|
# exist, add amount
|
||||||
self.position[stock_id]["amount"] += amount
|
self.position[stock_id]["amount"] += trade_amount
|
||||||
|
|
||||||
def sell_stock(self, stock_id, amount):
|
self.position["cash"] -= trade_val + cost
|
||||||
|
|
||||||
|
def sell_stock(self, stock_id, trade_val, cost, trade_price):
|
||||||
|
trade_amount = trade_val / trade_price
|
||||||
if stock_id not in self.position:
|
if stock_id not in self.position:
|
||||||
raise KeyError("{} not in current position".format(stock_id))
|
raise KeyError("{} not in current position".format(stock_id))
|
||||||
else:
|
else:
|
||||||
# decrease the amount of stock
|
# decrease the amount of stock
|
||||||
self.position[stock_id]["amount"] -= amount
|
self.position[stock_id]["amount"] -= trade_amount
|
||||||
# check if to delete
|
# check if to delete
|
||||||
if self.position[stock_id]["amount"] < -1e-5:
|
if self.position[stock_id]["amount"] < -1e-5:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"only have {} {}, require {}".format(self.position[stock_id]["amount"], stock_id, amount)
|
"only have {} {}, require {}".format(self.position[stock_id]["amount"], stock_id, trade_amount)
|
||||||
)
|
)
|
||||||
elif abs(self.position[stock_id]["amount"]) <= 1e-5:
|
elif abs(self.position[stock_id]["amount"]) <= 1e-5:
|
||||||
self.del_stock(stock_id)
|
self.del_stock(stock_id)
|
||||||
|
|
||||||
|
self.position["cash"] += trade_val - cost
|
||||||
|
|
||||||
def del_stock(self, stock_id):
|
def del_stock(self, stock_id):
|
||||||
del self.position[stock_id]
|
del self.position[stock_id]
|
||||||
|
|
||||||
def update_order(self, order, trade_price):
|
def update_order(self, order, trade_val, cost, trade_price):
|
||||||
# handle order, order is a order class, defined in exchange.py
|
# handle order, order is a order class, defined in exchange.py
|
||||||
if order.direction == Order.BUY:
|
if order.direction == Order.BUY:
|
||||||
# BUY
|
# BUY
|
||||||
self.buy_stock(stock_id=order.stock_id, amount=order.deal_amount, price=trade_price)
|
self.buy_stock(order.stock_id, trade_val, cost, trade_price)
|
||||||
elif order.direction == Order.SELL:
|
elif order.direction == Order.SELL:
|
||||||
# SELL
|
# SELL
|
||||||
self.sell_stock(stock_id=order.stock_id, amount=order.deal_amount)
|
self.sell_stock(order.stock_id, trade_val, cost, trade_price)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError("do not suppotr order direction {}".format(order.direction))
|
raise NotImplementedError("do not suppotr order direction {}".format(order.direction))
|
||||||
|
|
||||||
|
|||||||
@@ -238,7 +238,6 @@ class TopkDropoutStrategy(BaseStrategy, ListAdjustTimer):
|
|||||||
sell_order_list = []
|
sell_order_list = []
|
||||||
buy_order_list = []
|
buy_order_list = []
|
||||||
# load score
|
# load score
|
||||||
cash = current_temp.get_cash()
|
|
||||||
current_stock_list = current_temp.get_stock_list()
|
current_stock_list = current_temp.get_stock_list()
|
||||||
last = score_series.reindex(current_stock_list).sort_values(ascending=False).index
|
last = score_series.reindex(current_stock_list).sort_values(ascending=False).index
|
||||||
today = (
|
today = (
|
||||||
@@ -275,8 +274,6 @@ class TopkDropoutStrategy(BaseStrategy, ListAdjustTimer):
|
|||||||
if trade_exchange.check_order(sell_order):
|
if trade_exchange.check_order(sell_order):
|
||||||
sell_order_list.append(sell_order)
|
sell_order_list.append(sell_order)
|
||||||
trade_val, trade_cost, trade_price = trade_exchange.deal_order(sell_order, position=current_temp)
|
trade_val, trade_cost, trade_price = trade_exchange.deal_order(sell_order, position=current_temp)
|
||||||
# update cash
|
|
||||||
cash += trade_val - trade_cost
|
|
||||||
# sold
|
# sold
|
||||||
del self.stock_count[code]
|
del self.stock_count[code]
|
||||||
else:
|
else:
|
||||||
@@ -292,7 +289,7 @@ class TopkDropoutStrategy(BaseStrategy, ListAdjustTimer):
|
|||||||
# buy new stock
|
# buy new stock
|
||||||
# note the current has been changed
|
# note the current has been changed
|
||||||
current_stock_list = current_temp.get_stock_list()
|
current_stock_list = current_temp.get_stock_list()
|
||||||
value = cash * self.risk_degree / len(buy) if len(buy) > 0 else 0
|
value = current_temp.get_cash() * self.risk_degree / len(buy) if len(buy) > 0 else 0
|
||||||
|
|
||||||
# open_cost should be considered in the real trading environment, while the backtest in evaluate.py does not consider it
|
# open_cost should be considered in the real trading environment, while the backtest in evaluate.py does not consider it
|
||||||
# as the aim of demo is to accomplish same strategy as evaluate.py, so comment out this line
|
# as the aim of demo is to accomplish same strategy as evaluate.py, so comment out this line
|
||||||
|
|||||||
Reference in New Issue
Block a user