"""Small deterministic JoinQuant API harness for local contract tests.""" import datetime from types import SimpleNamespace class FakePosition(object): def __init__(self, total_amount=0, closeable_amount=None): self.total_amount = int(total_amount) self.closeable_amount = int( total_amount if closeable_amount is None else closeable_amount ) class FakeJoinQuantHarness(object): """Install fake hosted functions into a strategy module.""" def __init__( self, histories, total_value=1_000_000.0, positions=None, st_symbols=None, ): self.histories = { symbol: [float(value) for value in values] for symbol, values in histories.items() } self.options = {} self.benchmark = None self.order_cost = None self.slippage = None self.schedules = [] self.orders = [] self.order_styles = [] self.last_index_request = None self.last_history_request = None self.last_extras_request = None self.st_symbols = set(st_symbols or []) self.current_data = { symbol: SimpleNamespace( paused=False, is_st=False, high_limit=9999.0, low_limit=0.01, ) for symbol in histories } self.context = SimpleNamespace( current_dt=datetime.datetime(2026, 7, 20, 9, 30), previous_date=datetime.date(2026, 7, 17), portfolio=SimpleNamespace( total_value=float(total_value), positions=dict(positions or {}), ) ) self.g = SimpleNamespace() def install(self, module): module.g = self.g module.set_option = self.set_option module.run_daily = self.run_daily module.attribute_history = self.attribute_history module.history = self.history module.get_index_stocks = self.get_index_stocks module.get_extras = self.get_extras module.set_benchmark = self.set_benchmark module.set_order_cost = self.set_order_cost module.set_slippage = self.set_slippage module.OrderCost = self.OrderCost module.PriceRelatedSlippage = self.PriceRelatedSlippage module.LimitOrderStyle = self.LimitOrderStyle module.order_target = self.order_target module.get_current_data = self.get_current_data return self def set_option(self, key, value): self.options[key] = value def set_benchmark(self, symbol): self.benchmark = symbol @staticmethod def OrderCost(**kwargs): return SimpleNamespace(**kwargs) @staticmethod def PriceRelatedSlippage(value): return SimpleNamespace(value=float(value)) @staticmethod def LimitOrderStyle(limit_price): return SimpleNamespace( kind="limit", limit_price=float(limit_price), ) def set_order_cost(self, cost, type=None): self.order_cost = {"cost": cost, "type": type} def set_slippage(self, slippage, type=None): self.slippage = {"slippage": slippage, "type": type} def run_daily(self, callback, time="open"): self.schedules.append((callback, time)) def attribute_history( self, symbol, count, unit="1d", fields=None, skip_paused=False, df=False, fq="pre", ): del unit, fields, skip_paused, df, fq return {"close": self.histories[symbol][-int(count) :]} def history( self, count, unit="1d", field="close", security_list=None, df=False, skip_paused=False, fq="pre", ): del unit, field, df, skip_paused, fq symbols = list(security_list or self.histories) self.last_history_request = { "count": int(count), "security_list": symbols, } return { symbol: self.histories[symbol][-int(count) :] for symbol in symbols } def get_index_stocks(self, index_symbol, date=None): self.last_index_request = { "index_symbol": index_symbol, "date": date, } return sorted(self.histories) def get_extras( self, info, security_list, end_date=None, count=1, df=False, ): self.last_extras_request = { "info": info, "security_list": list(security_list), "end_date": end_date, "count": count, "df": df, } return { symbol: [symbol in self.st_symbols] for symbol in security_list } def order_target(self, symbol, quantity, style=None): self.orders.append((symbol, int(quantity))) self.order_styles.append((symbol, style)) return SimpleNamespace(security=symbol, target_quantity=int(quantity)) def get_current_data(self): return self.current_data def initialize(self, module): self.install(module) module.initialize(self.context) return self def run_scheduled(self, index=0): callback = self.schedules[index][0] return callback(self.context) def advance_session(self, days=1): previous = self.context.current_dt.date() self.context.previous_date = previous self.context.current_dt += datetime.timedelta(days=int(days)) return self