159 lines
4.3 KiB
Python
159 lines
4.3 KiB
Python
"""Deterministic fake QMT ContextInfo and passorder recorder."""
|
|
|
|
import datetime
|
|
from types import SimpleNamespace
|
|
|
|
|
|
class FakeFrame(object):
|
|
def __init__(self, closes):
|
|
self._closes = list(closes)
|
|
|
|
def __getitem__(self, key):
|
|
if key != "close":
|
|
raise KeyError(key)
|
|
return list(self._closes)
|
|
|
|
|
|
class FakeQmtContext(object):
|
|
def __init__(
|
|
self,
|
|
histories,
|
|
asset=1_000_000.0,
|
|
positions=None,
|
|
bar_time=None,
|
|
trade_mode="backtest",
|
|
params=None,
|
|
st_periods=None,
|
|
):
|
|
self.histories = {
|
|
symbol: [float(value) for value in values]
|
|
for symbol, values in histories.items()
|
|
}
|
|
self.trade_mode = trade_mode
|
|
self.do_back_test = trade_mode == "backtest"
|
|
self._param = {"asset": float(asset), "trade_mode": trade_mode}
|
|
self._param.update(params or {})
|
|
self.barpos = 0
|
|
self._bar_time = bar_time or datetime.datetime(2026, 7, 20, 15, 0)
|
|
self._positions = list(positions or [])
|
|
self._asset = float(asset)
|
|
self.universe = []
|
|
self.last_market_request = None
|
|
self.last_sector_request = None
|
|
self.commission = None
|
|
self.slippage = None
|
|
self.st_periods = dict(st_periods or {})
|
|
|
|
def set_universe(self, symbols):
|
|
self.universe = list(symbols)
|
|
|
|
def set_commission(self, commission_type, commission_list):
|
|
self.commission = {
|
|
"type": int(commission_type),
|
|
"values": list(commission_list),
|
|
}
|
|
|
|
def set_slippage(self, slippage_type, slippage):
|
|
self.slippage = {
|
|
"type": int(slippage_type),
|
|
"value": float(slippage),
|
|
}
|
|
|
|
def get_bar_timetag(self, barpos):
|
|
del barpos
|
|
return int(self._bar_time.timestamp() * 1000)
|
|
|
|
def is_last_bar(self):
|
|
return True
|
|
|
|
def get_market_data_ex(
|
|
self,
|
|
fields,
|
|
stock_code,
|
|
period,
|
|
start_time,
|
|
end_time,
|
|
count,
|
|
dividend_type,
|
|
fill_data,
|
|
subscribe,
|
|
):
|
|
self.last_market_request = {
|
|
"fields": fields,
|
|
"stock_code": stock_code,
|
|
"period": period,
|
|
"start_time": start_time,
|
|
"end_time": end_time,
|
|
"count": count,
|
|
"dividend_type": dividend_type,
|
|
"fill_data": fill_data,
|
|
"subscribe": subscribe,
|
|
}
|
|
return {
|
|
symbol: FakeFrame(self.histories[symbol][-int(count) :])
|
|
for symbol in stock_code
|
|
}
|
|
|
|
def get_stock_list_in_sector(self, sector_name, timetag=None):
|
|
self.last_sector_request = {
|
|
"sector_name": sector_name,
|
|
"timetag": timetag,
|
|
}
|
|
return sorted(self.histories)
|
|
|
|
def get_his_st_data(self, symbol):
|
|
return dict(self.st_periods.get(symbol, {}))
|
|
|
|
def get_trade_detail_data(self, account_id, account_type, kind):
|
|
del account_id, account_type
|
|
if str(kind).lower() == "position":
|
|
return list(self._positions)
|
|
if str(kind).lower() == "account":
|
|
return [SimpleNamespace(total_asset=self._asset)]
|
|
return []
|
|
|
|
|
|
class FakeQmtHarness(object):
|
|
def __init__(self, context):
|
|
self.context = context
|
|
self.orders = []
|
|
|
|
def install(self, module):
|
|
module.passorder = self.passorder
|
|
return self
|
|
|
|
def passorder(
|
|
self,
|
|
operation,
|
|
order_type,
|
|
account_id,
|
|
order_code,
|
|
price_type,
|
|
price,
|
|
volume,
|
|
strategy_name,
|
|
quick_trade,
|
|
user_order_id,
|
|
context,
|
|
):
|
|
self.orders.append(
|
|
{
|
|
"operation": operation,
|
|
"order_type": order_type,
|
|
"account_id": account_id,
|
|
"order_code": order_code,
|
|
"price_type": price_type,
|
|
"price": price,
|
|
"volume": volume,
|
|
"strategy_name": strategy_name,
|
|
"quick_trade": quick_trade,
|
|
"user_order_id": user_order_id,
|
|
"context": context,
|
|
}
|
|
)
|
|
|
|
def run(self, module):
|
|
self.install(module)
|
|
module.init(self.context)
|
|
return module.handlebar(self.context)
|