OHLC's use timestamps instead of string dates

This commit is contained in:
Tim
2024-02-13 23:50:57 -04:00
parent c8f65a6306
commit 9b6a9c3cda
4 changed files with 18 additions and 38 deletions

View File

@@ -10,8 +10,10 @@ dec = Decimal
def now(): def now():
return datetime.now(timezone.utc) return datetime.now(timezone.utc)
def timestamp(): def timestamp(when=None):
return int(datetime.now().timestamp()) if when is None:
when = datetime.now()
return int(when.timestamp())
def from_timestamp(ts): def from_timestamp(ts):
return datetime.fromtimestamp(ts, timezone.utc) return datetime.fromtimestamp(ts, timezone.utc)

View File

@@ -7,7 +7,6 @@ from omegaconf.errors import OmegaConfBaseException
from .schema import Config from .schema import Config
from .standard_accounts import default_accounts_config from .standard_accounts import default_accounts_config
from .standard_tokens import default_token_config
schema = OmegaConf.structured(Config()) schema = OmegaConf.structured(Config())
@@ -20,7 +19,6 @@ def load_config():
# noinspection PyTypeChecker # noinspection PyTypeChecker
result:ConfigDict = OmegaConf.merge( result:ConfigDict = OmegaConf.merge(
schema, schema,
load_tokens(),
load_accounts(), load_accounts(),
from_toml('pool.toml'), from_toml('pool.toml'),
from_toml('dexorder.toml'), from_toml('dexorder.toml'),
@@ -31,15 +29,6 @@ def load_config():
return result return result
def load_tokens():
token_conf = OmegaConf.create({'tokens': default_token_config})
try:
OmegaConf.merge(schema, token_conf)
return token_conf
except OmegaConfBaseException as _x:
raise ConfigException(f'Error while processing default tokens:\n{_x}')
def load_accounts(): def load_accounts():
accounts_conf = OmegaConf.create({'accounts': default_accounts_config}) accounts_conf = OmegaConf.create({'accounts': default_accounts_config})
try: try:

View File

@@ -21,19 +21,8 @@ class Config:
polling: float = 0 # seconds between queries for a new block. 0 disables polling and uses a websocket subscription on ws_url instead polling: float = 0 # seconds between queries for a new block. 0 disables polling and uses a websocket subscription on ws_url instead
backfill: int = 0 # if not 0, then runner will initialize an empty database by backfilling from the given block height backfill: int = 0 # if not 0, then runner will initialize an empty database by backfilling from the given block height
tokens: list['TokenConfig'] = field(default_factory=list)
account: Optional[str] = None # may be a private key or an account alias account: Optional[str] = None # may be a private key or an account alias
accounts: Optional[dict[str,str]] = field(default_factory=dict) # account aliases accounts: Optional[dict[str,str]] = field(default_factory=dict) # account aliases
deployments: Optional[dict[str,str]] = field(default_factory=dict) deployments: Optional[dict[str,str]] = field(default_factory=dict)
min_gas: str = '0' min_gas: str = '0'
@dataclass
class TokenConfig:
name: str
symbol: str
decimals: int
chain: str
address: str
abi: Optional[str] = None

View File

@@ -7,7 +7,7 @@ from typing import Optional, NamedTuple, Reversible, Union
from cachetools import LFUCache from cachetools import LFUCache
from dexorder import dec, config, from_isotime, minutely, from_timestamp from dexorder import dec, config, from_timestamp, timestamp
from dexorder.base.chain import current_chain from dexorder.base.chain import current_chain
from dexorder.blockstate import BlockDict, DiffItem, current_blockstate from dexorder.blockstate import BlockDict, DiffItem, current_blockstate
from dexorder.blockstate.diff import DiffEntryItem from dexorder.blockstate.diff import DiffEntryItem
@@ -24,16 +24,16 @@ OHLC_PERIODS = [
OHLC_DATE_ROOT = datetime(2009, 1, 4, tzinfo=timezone.utc) # Sunday before Bitcoin Genesis OHLC_DATE_ROOT = datetime(2009, 1, 4, tzinfo=timezone.utc) # Sunday before Bitcoin Genesis
# OHLC's are stored as [time, open, high, low, close] string values. If there was no data during the interval, # OHLC's are stored as [timestamp, open, high, low, close] with prices as string values. If there was no data during
# then open, high, and low are None but the close value is carried over from the previous interval. # the interval, then open, high, and low are None but the close value is carried over from the previous interval.
OHLC = list[str] # typedef OHLC = list[Union[None,int,str]] # typedef
def opt_dec(v): def opt_dec(v):
return None if v is None else dec(v) return None if v is None else dec(v)
def dt(v): def dt(v):
return v if isinstance(v, datetime) else from_isotime(v) return v if isinstance(v, datetime) else from_timestamp(v)
@dataclass @dataclass
class NativeOHLC: class NativeOHLC:
@@ -50,7 +50,7 @@ class NativeOHLC:
@property @property
def ohlc(self) -> OHLC: def ohlc(self) -> OHLC:
return [ return [
minutely(self.start), timestamp(self.start),
None if self.open is None else str(self.open), None if self.open is None else str(self.open),
None if self.high is None else str(self.high), None if self.high is None else str(self.high),
None if self.low is None else str(self.low), None if self.low is None else str(self.low),
@@ -154,13 +154,13 @@ class OHLCRepository:
return # do not track symbols which have not been explicity set up return # do not track symbols which have not been explicity set up
p = str(price) p = str(price)
historical = [] historical = []
updated = [OHLC((minutely(ohlc_start_time(time, period)), p, p, p, p))] updated = [OHLC((timestamp(ohlc_start_time(time, period)), p, p, p, p))]
# log.debug(f'\tcreated new bars {updated}') # log.debug(f'\tcreated new bars {updated}')
else: else:
updated = update_ohlc(historical[-1], period, time, price) updated = update_ohlc(historical[-1], period, time, price)
# drop any historical bars that are older than we need # drop any historical bars that are older than we need
oldest_needed = from_timestamp(current_blockstate.get().root_block.timestamp) - period # cover the root block time plus one period prior oldest_needed = from_timestamp(current_blockstate.get().root_block.timestamp) - period # cover the root block time plus one period prior
trim = (oldest_needed - from_isotime(historical[0][0])) // period trim = (oldest_needed - from_timestamp(historical[0][0])) // period
if trim > 0: if trim > 0:
historical = historical[trim:] historical = historical[trim:]
@@ -168,8 +168,8 @@ class OHLCRepository:
if not historical or not updated: if not historical or not updated:
updated = historical + updated updated = historical + updated
else: else:
last_bar = from_isotime(historical[-1][0]) last_bar = from_timestamp(historical[-1][0])
first_updated = from_isotime(updated[0][0]) first_updated = from_timestamp(updated[0][0])
overlap = (first_updated - last_bar) // period + 1 overlap = (first_updated - last_bar) // period + 1
updated = historical[:-overlap] + updated if overlap > 0 else historical + updated updated = historical[:-overlap] + updated if overlap > 0 else historical + updated
# log.debug(f'\tnew recents: {updated}') # log.debug(f'\tnew recents: {updated}')
@@ -187,17 +187,17 @@ class OHLCRepository:
if not chunk: if not chunk:
chunk = [ohlc] chunk = [ohlc]
else: else:
start = from_isotime(chunk[0][0]) start = from_timestamp(chunk[0][0])
index = (time - start) // period index = (time - start) // period
# log.debug(f'save {symbol} {ohlc_name(period)} chunk {start} index {index} <= {len(chunk)}') # log.debug(f'save {symbol} {ohlc_name(period)} chunk {start} index {index} <= {len(chunk)}')
if index > len(chunk): if index > len(chunk):
log.error(f'chunk gap: {index} > {len(chunk)} {symbol} {period_name(period)} {ohlc}'+''.join(f'\n\t{c}' for c in chunk)) log.error(f'chunk gap: {index} > {len(chunk)} {symbol} {period_name(period)} {ohlc}'+''.join(f'\n\t{c}' for c in chunk))
exit(1) exit(1)
if index == len(chunk): if index == len(chunk):
assert from_isotime(chunk[-1][0]) + period == time assert from_timestamp(chunk[-1][0]) + period == time
chunk.append(ohlc) chunk.append(ohlc)
else: else:
assert from_isotime(chunk[index][0]) == time assert from_timestamp(chunk[index][0]) == time
chunk[index] = ohlc chunk[index] = ohlc
self.save_chunk(symbol, period, chunk) self.save_chunk(symbol, period, chunk)
@@ -222,7 +222,7 @@ class OHLCRepository:
def save_chunk(self, symbol: str, period: timedelta, chunk: list[OHLC]): def save_chunk(self, symbol: str, period: timedelta, chunk: list[OHLC]):
if not chunk: if not chunk:
return return
path = self.chunk_path(symbol, period, from_isotime(chunk[0][0])) path = self.chunk_path(symbol, period, from_timestamp(chunk[0][0]))
for _ in range(2): for _ in range(2):
try: try:
with open(path, 'w') as file: with open(path, 'w') as file: