From 31e74ed92b4e8101d9e1868d34ae44aac0b8ffb3 Mon Sep 17 00:00:00 2001 From: Peter Dekkers Date: Sat, 15 Jun 2024 20:47:32 +0200 Subject: [PATCH] improved random walk --- roboquant/feeds/randomwalk.py | 28 ++++++++++++++++++++-------- roboquant/strategies/ordersizer.py | 29 ----------------------------- 2 files changed, 20 insertions(+), 37 deletions(-) delete mode 100644 roboquant/strategies/ordersizer.py diff --git a/roboquant/feeds/randomwalk.py b/roboquant/feeds/randomwalk.py index 986246a..bf1ad1e 100644 --- a/roboquant/feeds/randomwalk.py +++ b/roboquant/feeds/randomwalk.py @@ -6,7 +6,7 @@ import numpy as np -from roboquant.event import Bar, Trade +from roboquant.event import Bar, Trade, Quote from .historic import HistoricFeed @@ -18,7 +18,7 @@ def __init__( self, n_symbols: int = 10, n_prices: int = 1_000, - item_type: Literal["bar", "trade"] = "bar", + item_type: Literal["bar", "trade", "quote"] = "bar", start_date: str | datetime = "2020-01-01T00:00:00+00:00", frequency=timedelta(days=1), start_price_min: float = 50.0, @@ -36,26 +36,38 @@ def __init__( start_date = start_date if isinstance(start_date, datetime) else datetime.fromisoformat(start_date) start_date = start_date.astimezone(timezone.utc) timeline = [start_date + frequency * i for i in range(n_prices)] + self.stdev = stdev - item_gen = self.__get_bar if item_type == "bar" else self.__get_trade + match item_type: + case "bar": item_gen = self.__get_bar + case "trade": item_gen = self.__get_trade + case "quote": item_gen = self.__get_quote + case _: raise ValueError("unsupported item_type", item_type) for symbol in symbols: prices = self.__price_path(rnd, n_prices, stdev, start_price_min, start_price_max) for i in range(n_prices): - item = item_gen(symbol, prices[i], volume) + item = item_gen(symbol, prices[i], volume, stdev/2.0) self._add_item(timeline[i], item) @staticmethod - def __get_trade(symbol, price, volume): + def __get_trade(symbol, price, volume, _): return Trade(symbol, price, volume) @staticmethod - def __get_bar(symbol, price, volume): - high = price * (1.0 + abs(random.gauss(mu=0.0, sigma=1.0))) - low = price * (1.0 - abs(random.gauss(mu=0.0, sigma=1.0))) + def __get_bar(symbol, price, volume, spread): + high = price * (1.0 + abs(random.gauss(mu=0.0, sigma=spread))) + low = price * (1.0 - abs(random.gauss(mu=0.0, sigma=spread))) close = random.uniform(low, high) return Bar(symbol, array("f", [price, high, low, close, volume])) + @staticmethod + def __get_quote(symbol, price, volume, spread): + spread = abs(random.gauss(mu=0.0, sigma=spread)) * price / 2.0 + ask = price + spread + bid = price - spread + return Quote(symbol, array("f", [price, ask, volume, bid, volume])) + @staticmethod def __get_symbols( rnd, diff --git a/roboquant/strategies/ordersizer.py b/roboquant/strategies/ordersizer.py deleted file mode 100644 index 3c4c12b..0000000 --- a/roboquant/strategies/ordersizer.py +++ /dev/null @@ -1,29 +0,0 @@ -from decimal import Decimal -from roboquant.account import Account - - -class OrderSizer: - - def __init__(self, account: Account): - self.account = account - self.buying_power = account.buying_power - self.equity = account.equity() - self.max_order_size = self.equity * 0.2 - self.size_digits = 0 - - def is_reduction(self, symbol: str, size: Decimal) -> bool: - """Determine the kind of change a certain action would have on the position""" - pos_size = self.account.get_position_size(symbol) - return abs(size + pos_size) < abs(pos_size) - - def size(self, symbol: str, price: float, percentage: float) -> Decimal: - contract_price = self.account.contract_value(symbol, price) - size = Decimal(percentage * self.equity * 0.2 / contract_price) - size = round(size, self.size_digits) - if not self.is_reduction(symbol, size): - contract_value = contract_price * float(size) - if self.buying_power > contract_value: - self.buying_power -= contract_value - return size - return Decimal() - return size