Module curvepy.quotes
Expand source code
from .curve import Curve, MIN_STEP
from .map import Map
from .points import Points
from intervalpy import Interval
from pyduration import Duration
OHLC_KEYS = ['open', 'high', 'low', 'close', 'volume']
OHLC_POINT_COUNT = len(OHLC_KEYS)
OHLC_STEPS = OHLC_POINT_COUNT - 1
QUOTE_MIN_STEP_COEFFICIENT = 0.1
OPEN = 0
HIGH = 1
LOW = 2
CLOSE = 3
VOLUME = 4
class Quotes(Curve):
"""
Represents quotes as [open, high, low, close, (volume)].
"""
@property
def close(self):
if self._close is None:
self._close = Map(
self,
lambda q: q[CLOSE],
skip_none=True,
name='close'
)
return self._close
@property
def open(self):
if self._open is None:
self._open = Map(
self,
lambda q: q[OPEN],
skip_none=True,
name='open'
)
return self._open
@property
def high(self):
if self._high is None:
self._high = Map(
self,
lambda q: q[HIGH],
skip_none=True,
name='high'
)
return self._high
@property
def low(self):
if self._low is None:
self._low = Map(
self,
lambda q: q[LOW],
skip_none=True,
name='low'
)
return self._low
@property
def hl2(self):
if self._hl2 is None:
self._hl2 = Map(
self,
lambda q: (q[HIGH] + q[LOW]) / 2,
skip_none=True,
name='hl2'
)
return self._hl2
@property
def volume(self):
if self._volume is None:
self._volume = Map(
self,
lambda q: q[VOLUME],
skip_none=True,
name='volume'
)
return self._volume
def get_domain(self):
return self._quote_points.domain
def get_quote_domain(self):
domain = self._quote_points.domain
if domain.is_empty:
return domain
return self.duration.span(domain, start_open=False)
def __init__(self, duration, quote_points=None, encoder=None, **kwargs):
"""
`quote_points` are assumed to be in the form [timestamp, [o, h, l, c, v]],
or in a suitable form for `encoder`, in strict ascending order with no gaps
and with the same duration as the receiver.
If `encoder` is specified, then it is used to map the structure of data into
the structure of `quote_points`.
"""
duration = Duration.parse(duration)
self.duration = duration
super().__init__(min_step=duration.min_seconds * 0.01, **kwargs)
self.encoder = encoder
self._quote_points = Points(
[], interpolation=Points.interpolation.previous, uniform=duration.is_uniform)
self._quote_points.add_observer(begin=self.begin_update, end=self.end_update, prioritize=True)
self._close = None
self._open = None
self._high = None
self._low = None
self._hl2 = None
self._ohlc = None
self._volume = None
if quote_points is not None:
self.set(quote_points)
def __repr__(self):
try:
return f'quotes({self.duration})'
except Exception as e:
return super().__repr__() + f'({e})'
def last_quote(self):
return self.y_end()
def first_quote(self):
return self.y_start()
def get_range(self, domain=None, **kwargs):
quotes = self.sample(domain=domain, **kwargs)
low = None
high = None
for q in quotes:
if low is None or q.low < low:
low = q.low
if high is None or q.high > high:
high = q.high
if low is None or high is None:
return Interval.empty()
return Interval(low, high)
def ao(self):
"""
The Awesome Oscillator is an indicator used to measure market momentum.
AO calculates the difference of a 34 Period and 5 Period Simple Moving Averages.
The Simple Moving Averages that are used are not calculated using closing
price but rather each bar's midpoints. AO is generally used to affirm trends
or to anticipate possible reversals.
"""
uniform = self.duration.is_uniform
return self.hl2.sma(5, uniform=uniform) - self.hl2.sma(34, uniform=uniform)
def alligator(self):
"""
The Alligator indicator uses three smoothed moving averages, set at five,
eight and 13 periods, which are all Fibonacci numbers. The initial smoothed
average is calculated with a simple moving average (SMA), adding additional
smoothed averages that slow down indicator turns.
"""
uniform = self.duration.is_uniform
jaw = self.hl2.sma(13, uniform=uniform).offset(8, duration=self.duration)
teeth = self.hl2.sma(8, uniform=uniform).offset(5, duration=self.duration)
lips = self.hl2.sma(5, uniform=uniform).offset(3, duration=self.duration)
return jaw, teeth, lips
def trailing_high(self, degree, is_period=False):
return self.high.trailing_max(degree, is_period=is_period, interpolation=-1, uniform=self.duration.is_uniform)
def trailing_low(self, degree, is_period=False):
return self.low.trailing_max(degree, is_period=is_period, interpolation=-1, uniform=self.duration.is_uniform)
def append(self, quote_point):
"""
`quote_points` are assumed to be in the form [timestamp, [o, h, l, c, v]],
or in a suitable form for `encoder`, in strict ascending order with no gaps
and with the same duration as the receiver.
"""
self.append_list([self.encode_one(quote_point)])
def append_list(self, quote_points):
"""
`quote_points` are assumed to be in the form [timestamp, [o, h, l, c, v]],
or in a suitable form for `encoder`, in strict ascending order with no gaps
and with the same duration as the receiver.
"""
if self.domain.is_empty:
return self.set(quote_points)
self._quote_points.append_list(self.encode_many(quote_points))
def set(self, quote_points):
"""
`quote_points` are assumed to be in the form [timestamp, [o, h, l, c, v]],
or in a suitable form for `encoder`, in strict ascending order with no gaps
and with the same duration as the receiver.
"""
self._quote_points.set(self.encode_many(quote_points))
def encode_one(self, quote_point):
if self.encoder is not None:
return self.encoder(quote_point)
return quote_point
def encode_many(self, quote_points):
if self.encoder is not None:
return [self.encoder(p) for p in quote_points]
return quote_points
def sample(self, domain=None, min_step=MIN_STEP, step=None):
points = self.sample_points(
domain=domain,
min_step=min_step,
step=step
)
return [p[1] for p in points]
def sample_points(self, domain=None, min_step=MIN_STEP, step=None):
domain = Interval.parse(domain, default_inf=True)
if domain.is_empty:
return []
pinterval = self.duration.span(domain, start_open=False)
return self._quote_points.sample_points(domain=pinterval, min_step=min_step, step=step)
def y(self, x):
return self._quote_points.y(x)
def x_next(self, x, min_step=MIN_STEP, limit=None):
# return self.duration.next(x)
return self._quote_points.x_next(x, min_step=min_step, limit=limit)
def x_previous(self, x, min_step=MIN_STEP, limit=None):
# return self.duration.previous(x)
return self._quote_points.x_previous(x, min_step=min_step, limit=limit)
Classes
class Quotes (duration, quote_points=None, encoder=None, **kwargs)
-
Represents quotes as [open, high, low, close, (volume)].
quote_points
are assumed to be in the form [timestamp, [o, h, l, c, v]], or in a suitable form forencoder
, in strict ascending order with no gaps and with the same duration as the receiver.If
encoder
is specified, then it is used to map the structure of data into the structure ofquote_points
.Expand source code
class Quotes(Curve): """ Represents quotes as [open, high, low, close, (volume)]. """ @property def close(self): if self._close is None: self._close = Map( self, lambda q: q[CLOSE], skip_none=True, name='close' ) return self._close @property def open(self): if self._open is None: self._open = Map( self, lambda q: q[OPEN], skip_none=True, name='open' ) return self._open @property def high(self): if self._high is None: self._high = Map( self, lambda q: q[HIGH], skip_none=True, name='high' ) return self._high @property def low(self): if self._low is None: self._low = Map( self, lambda q: q[LOW], skip_none=True, name='low' ) return self._low @property def hl2(self): if self._hl2 is None: self._hl2 = Map( self, lambda q: (q[HIGH] + q[LOW]) / 2, skip_none=True, name='hl2' ) return self._hl2 @property def volume(self): if self._volume is None: self._volume = Map( self, lambda q: q[VOLUME], skip_none=True, name='volume' ) return self._volume def get_domain(self): return self._quote_points.domain def get_quote_domain(self): domain = self._quote_points.domain if domain.is_empty: return domain return self.duration.span(domain, start_open=False) def __init__(self, duration, quote_points=None, encoder=None, **kwargs): """ `quote_points` are assumed to be in the form [timestamp, [o, h, l, c, v]], or in a suitable form for `encoder`, in strict ascending order with no gaps and with the same duration as the receiver. If `encoder` is specified, then it is used to map the structure of data into the structure of `quote_points`. """ duration = Duration.parse(duration) self.duration = duration super().__init__(min_step=duration.min_seconds * 0.01, **kwargs) self.encoder = encoder self._quote_points = Points( [], interpolation=Points.interpolation.previous, uniform=duration.is_uniform) self._quote_points.add_observer(begin=self.begin_update, end=self.end_update, prioritize=True) self._close = None self._open = None self._high = None self._low = None self._hl2 = None self._ohlc = None self._volume = None if quote_points is not None: self.set(quote_points) def __repr__(self): try: return f'quotes({self.duration})' except Exception as e: return super().__repr__() + f'({e})' def last_quote(self): return self.y_end() def first_quote(self): return self.y_start() def get_range(self, domain=None, **kwargs): quotes = self.sample(domain=domain, **kwargs) low = None high = None for q in quotes: if low is None or q.low < low: low = q.low if high is None or q.high > high: high = q.high if low is None or high is None: return Interval.empty() return Interval(low, high) def ao(self): """ The Awesome Oscillator is an indicator used to measure market momentum. AO calculates the difference of a 34 Period and 5 Period Simple Moving Averages. The Simple Moving Averages that are used are not calculated using closing price but rather each bar's midpoints. AO is generally used to affirm trends or to anticipate possible reversals. """ uniform = self.duration.is_uniform return self.hl2.sma(5, uniform=uniform) - self.hl2.sma(34, uniform=uniform) def alligator(self): """ The Alligator indicator uses three smoothed moving averages, set at five, eight and 13 periods, which are all Fibonacci numbers. The initial smoothed average is calculated with a simple moving average (SMA), adding additional smoothed averages that slow down indicator turns. """ uniform = self.duration.is_uniform jaw = self.hl2.sma(13, uniform=uniform).offset(8, duration=self.duration) teeth = self.hl2.sma(8, uniform=uniform).offset(5, duration=self.duration) lips = self.hl2.sma(5, uniform=uniform).offset(3, duration=self.duration) return jaw, teeth, lips def trailing_high(self, degree, is_period=False): return self.high.trailing_max(degree, is_period=is_period, interpolation=-1, uniform=self.duration.is_uniform) def trailing_low(self, degree, is_period=False): return self.low.trailing_max(degree, is_period=is_period, interpolation=-1, uniform=self.duration.is_uniform) def append(self, quote_point): """ `quote_points` are assumed to be in the form [timestamp, [o, h, l, c, v]], or in a suitable form for `encoder`, in strict ascending order with no gaps and with the same duration as the receiver. """ self.append_list([self.encode_one(quote_point)]) def append_list(self, quote_points): """ `quote_points` are assumed to be in the form [timestamp, [o, h, l, c, v]], or in a suitable form for `encoder`, in strict ascending order with no gaps and with the same duration as the receiver. """ if self.domain.is_empty: return self.set(quote_points) self._quote_points.append_list(self.encode_many(quote_points)) def set(self, quote_points): """ `quote_points` are assumed to be in the form [timestamp, [o, h, l, c, v]], or in a suitable form for `encoder`, in strict ascending order with no gaps and with the same duration as the receiver. """ self._quote_points.set(self.encode_many(quote_points)) def encode_one(self, quote_point): if self.encoder is not None: return self.encoder(quote_point) return quote_point def encode_many(self, quote_points): if self.encoder is not None: return [self.encoder(p) for p in quote_points] return quote_points def sample(self, domain=None, min_step=MIN_STEP, step=None): points = self.sample_points( domain=domain, min_step=min_step, step=step ) return [p[1] for p in points] def sample_points(self, domain=None, min_step=MIN_STEP, step=None): domain = Interval.parse(domain, default_inf=True) if domain.is_empty: return [] pinterval = self.duration.span(domain, start_open=False) return self._quote_points.sample_points(domain=pinterval, min_step=min_step, step=step) def y(self, x): return self._quote_points.y(x) def x_next(self, x, min_step=MIN_STEP, limit=None): # return self.duration.next(x) return self._quote_points.x_next(x, min_step=min_step, limit=limit) def x_previous(self, x, min_step=MIN_STEP, limit=None): # return self.duration.previous(x) return self._quote_points.x_previous(x, min_step=min_step, limit=limit)
Ancestors
Instance variables
var close
-
Expand source code
@property def close(self): if self._close is None: self._close = Map( self, lambda q: q[CLOSE], skip_none=True, name='close' ) return self._close
var high
-
Expand source code
@property def high(self): if self._high is None: self._high = Map( self, lambda q: q[HIGH], skip_none=True, name='high' ) return self._high
var hl2
-
Expand source code
@property def hl2(self): if self._hl2 is None: self._hl2 = Map( self, lambda q: (q[HIGH] + q[LOW]) / 2, skip_none=True, name='hl2' ) return self._hl2
var low
-
Expand source code
@property def low(self): if self._low is None: self._low = Map( self, lambda q: q[LOW], skip_none=True, name='low' ) return self._low
var open
-
Expand source code
@property def open(self): if self._open is None: self._open = Map( self, lambda q: q[OPEN], skip_none=True, name='open' ) return self._open
var volume
-
Expand source code
@property def volume(self): if self._volume is None: self._volume = Map( self, lambda q: q[VOLUME], skip_none=True, name='volume' ) return self._volume
Methods
def alligator(self)
-
The Alligator indicator uses three smoothed moving averages, set at five, eight and 13 periods, which are all Fibonacci numbers. The initial smoothed average is calculated with a simple moving average (SMA), adding additional smoothed averages that slow down indicator turns.
Expand source code
def alligator(self): """ The Alligator indicator uses three smoothed moving averages, set at five, eight and 13 periods, which are all Fibonacci numbers. The initial smoothed average is calculated with a simple moving average (SMA), adding additional smoothed averages that slow down indicator turns. """ uniform = self.duration.is_uniform jaw = self.hl2.sma(13, uniform=uniform).offset(8, duration=self.duration) teeth = self.hl2.sma(8, uniform=uniform).offset(5, duration=self.duration) lips = self.hl2.sma(5, uniform=uniform).offset(3, duration=self.duration) return jaw, teeth, lips
def ao(self)
-
The Awesome Oscillator is an indicator used to measure market momentum. AO calculates the difference of a 34 Period and 5 Period Simple Moving Averages. The Simple Moving Averages that are used are not calculated using closing price but rather each bar's midpoints. AO is generally used to affirm trends or to anticipate possible reversals.
Expand source code
def ao(self): """ The Awesome Oscillator is an indicator used to measure market momentum. AO calculates the difference of a 34 Period and 5 Period Simple Moving Averages. The Simple Moving Averages that are used are not calculated using closing price but rather each bar's midpoints. AO is generally used to affirm trends or to anticipate possible reversals. """ uniform = self.duration.is_uniform return self.hl2.sma(5, uniform=uniform) - self.hl2.sma(34, uniform=uniform)
def append(self, quote_point)
-
quote_points
are assumed to be in the form [timestamp, [o, h, l, c, v]], or in a suitable form forencoder
, in strict ascending order with no gaps and with the same duration as the receiver.Expand source code
def append(self, quote_point): """ `quote_points` are assumed to be in the form [timestamp, [o, h, l, c, v]], or in a suitable form for `encoder`, in strict ascending order with no gaps and with the same duration as the receiver. """ self.append_list([self.encode_one(quote_point)])
def append_list(self, quote_points)
-
quote_points
are assumed to be in the form [timestamp, [o, h, l, c, v]], or in a suitable form forencoder
, in strict ascending order with no gaps and with the same duration as the receiver.Expand source code
def append_list(self, quote_points): """ `quote_points` are assumed to be in the form [timestamp, [o, h, l, c, v]], or in a suitable form for `encoder`, in strict ascending order with no gaps and with the same duration as the receiver. """ if self.domain.is_empty: return self.set(quote_points) self._quote_points.append_list(self.encode_many(quote_points))
def encode_many(self, quote_points)
-
Expand source code
def encode_many(self, quote_points): if self.encoder is not None: return [self.encoder(p) for p in quote_points] return quote_points
def encode_one(self, quote_point)
-
Expand source code
def encode_one(self, quote_point): if self.encoder is not None: return self.encoder(quote_point) return quote_point
def first_quote(self)
-
Expand source code
def first_quote(self): return self.y_start()
def get_domain(self)
-
Expand source code
def get_domain(self): return self._quote_points.domain
def get_quote_domain(self)
-
Expand source code
def get_quote_domain(self): domain = self._quote_points.domain if domain.is_empty: return domain return self.duration.span(domain, start_open=False)
def get_range(self, domain=None, **kwargs)
-
Expand source code
def get_range(self, domain=None, **kwargs): quotes = self.sample(domain=domain, **kwargs) low = None high = None for q in quotes: if low is None or q.low < low: low = q.low if high is None or q.high > high: high = q.high if low is None or high is None: return Interval.empty() return Interval(low, high)
def last_quote(self)
-
Expand source code
def last_quote(self): return self.y_end()
def sample(self, domain=None, min_step=1e-05, step=None)
-
Expand source code
def sample(self, domain=None, min_step=MIN_STEP, step=None): points = self.sample_points( domain=domain, min_step=min_step, step=step ) return [p[1] for p in points]
def sample_points(self, domain=None, min_step=1e-05, step=None)
-
Expand source code
def sample_points(self, domain=None, min_step=MIN_STEP, step=None): domain = Interval.parse(domain, default_inf=True) if domain.is_empty: return [] pinterval = self.duration.span(domain, start_open=False) return self._quote_points.sample_points(domain=pinterval, min_step=min_step, step=step)
def set(self, quote_points)
-
quote_points
are assumed to be in the form [timestamp, [o, h, l, c, v]], or in a suitable form forencoder
, in strict ascending order with no gaps and with the same duration as the receiver.Expand source code
def set(self, quote_points): """ `quote_points` are assumed to be in the form [timestamp, [o, h, l, c, v]], or in a suitable form for `encoder`, in strict ascending order with no gaps and with the same duration as the receiver. """ self._quote_points.set(self.encode_many(quote_points))
def trailing_high(self, degree, is_period=False)
-
Expand source code
def trailing_high(self, degree, is_period=False): return self.high.trailing_max(degree, is_period=is_period, interpolation=-1, uniform=self.duration.is_uniform)
def trailing_low(self, degree, is_period=False)
-
Expand source code
def trailing_low(self, degree, is_period=False): return self.low.trailing_max(degree, is_period=is_period, interpolation=-1, uniform=self.duration.is_uniform)
def x_next(self, x, min_step=1e-05, limit=None)
-
Expand source code
def x_next(self, x, min_step=MIN_STEP, limit=None): # return self.duration.next(x) return self._quote_points.x_next(x, min_step=min_step, limit=limit)
def x_previous(self, x, min_step=1e-05, limit=None)
-
Expand source code
def x_previous(self, x, min_step=MIN_STEP, limit=None): # return self.duration.previous(x) return self._quote_points.x_previous(x, min_step=min_step, limit=limit)
def y(self, x)
-
Expand source code
def y(self, x): return self._quote_points.y(x)
Inherited members