Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions ib_async/ticker.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
nan = float("nan")


@dataclass
@dataclass(slots=True)
class Ticker:
"""
Current market data such as bid, ask, last price, etc. for a contract.
Expand Down Expand Up @@ -123,6 +123,7 @@ class Ticker:
regulatoryImbalance: float = nan
bboExchange: str = ""
snapshotPermissions: int = 0
updateEvent: Event = field(init=False)

def __post_init__(self):
self.updateEvent = TickerUpdateEvent("updateEvent")
Expand Down Expand Up @@ -258,14 +259,15 @@ def on_source(self, ticker):
self.emit(ticker.time, ticker.midpoint(), 0)


@dataclass
@dataclass(slots=True)
class Bar:
time: Optional[datetime]
open: float = nan
high: float = nan
low: float = nan
close: float = nan
volume: int = 0
wap: float = 0

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems lika "nan" is the convention for default. If you decide so, also conditions on ln 362 and 398 will need update to isNan(bar.wap).

Although looks like wap can only ever be nan/0 in TimeBar when bar gets created on timer without any input data, so maybe these conditions in Tick and Volume bars are unnecessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'll do a few tests with nan, I just realize that using wap = 0 is running my plots

count: int = 0


Expand Down Expand Up @@ -302,6 +304,11 @@ def on_source(self, time, price, size):
bar.high = max(bar.high, price)
bar.low = min(bar.low, price)
bar.close = price
# wap
if (bar.volume + size) == 0:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, how about:

new_volume = bar.volume + size
if new_volume != 0:  # Prevent division by zero in empty bar
    bar.wap = ((bar.wap * bar.volume) + (price * size)) / new_volume
bar.volume = new_volume

bar.wap = bar.wap
else:
bar.wap = ((bar.wap * bar.volume) + (price * size)) / (bar.volume + size)
bar.volume += size
bar.count += 1
self.bars.updateEvent.emit(self.bars, False)
Expand All @@ -310,7 +317,9 @@ def _on_timer(self, time):
if self.bars:
bar = self.bars[-1]
if isNan(bar.close) and len(self.bars) > 1:
bar.open = bar.high = bar.low = bar.close = self.bars[-2].close
bar.open = bar.high = bar.low = bar.close = bar.wap = self.bars[
-2
].close
self.bars.updateEvent.emit(self.bars, True)
self.emit(bar)
self.bars.append(Bar(time))
Expand All @@ -333,16 +342,25 @@ def __init__(self, count, source=None):

def on_source(self, time, price, size):
if not self.bars or self.bars[-1].count == self._count:
bar = Bar(time, price, price, price, price, size, 1)
bar = Bar(time, price, price, price, price, size, price, 1)
self.bars.append(bar)
else:
bar = self.bars[-1]
bar.high = max(bar.high, price)
bar.low = min(bar.low, price)
bar.close = price
# wap
if (bar.volume + size) == 0:
bar.wap = bar.wap
else:
bar.wap = ((bar.wap * bar.volume) + (price * size)) / (
bar.volume + size
)
bar.volume += size
bar.count += 1
if bar.count == self._count:
if bar.wap == 0:
bar.wap = bar.close
self.bars.updateEvent.emit(self.bars, True)
self.emit(self.bars)

Expand All @@ -360,15 +378,24 @@ def __init__(self, volume, source=None):

def on_source(self, time, price, size):
if not self.bars or self.bars[-1].volume >= self._volume:
bar = Bar(time, price, price, price, price, size, 1)
bar = Bar(time, price, price, price, price, size, price, 1)
self.bars.append(bar)
else:
bar = self.bars[-1]
bar.high = max(bar.high, price)
bar.low = min(bar.low, price)
# wap
bar.close = price
if (bar.volume + size) == 0:
bar.wap = bar.wap
else:
bar.wap = ((bar.wap * bar.volume) + (price * size)) / (
bar.volume + size
)
bar.volume += size
bar.count += 1
if bar.volume >= self._volume:
if bar.wap == 0:
bar.wap = bar.close
self.bars.updateEvent.emit(self.bars, True)
self.emit(self.bars)