Closed Pearce94 closed 6 years ago
As it is in the example, PriceTable only handles datetime and close . It is easy to extend the class with open/high/low/volume.
You say: "is there a way to pull" , you mean put I guess ? If you extend the pricetable you need to feed the addItem method also a full candle: datetime/O/H/L/C/volume
Does this help (I copied it from my code, and stripped a small piece, guess it should do the job)
class PriceTable(object):
def __init__(self, instrument, reserve=10000):
self.instrument = instrument
self._dt = [None] * reserve # allocate space for datetime
self._o = [None] * reserve # allocate space for open values
self._h = [None] * reserve # allocate space for high values
self._l = [None] * reserve # allocate space for low values
self._c = [None] * reserve # allocate space for close/last values
self._v = [None] * reserve # allocate space for volume values
self._events = {} # registered events
self.idx = 0
def fireEvent(self, name, *args, **kwargs):
if name in self._events:
f = self._events[name]
f(*args, **kwargs)
def setHandler(self, name, f):
if name not in self._events:
self._events[name] = Event()
self._events[name] += f
def addItem(self, dt, o, h, l, c, v):
self._dt[self.idx] = dt
self._o[self.idx] = o
self._h[self.idx] = h
self._l[self.idx] = l
self._c[self.idx] = c
self._v[self.idx] = v
self.idx += 1
self.fireEvent('onAddItem', self.idx)
def __len__(self):
return self.idx
def __getitem__(self, i):
def rr(_i):
if _i >= self.idx: # do not go beyond idx in the reserved items
raise IndexError("list assignment index out of range")
if _i < 0:
_i = self.idx + _i # the actual end of the array
return (self._dt[_i], self._o[_i],
self._h[_i],
self._l[_i],
self._c[_i],
self._v[_i])
if isinstance(i, int):
return rr(i)
elif isinstance(i, slice):
return [rr(j) for j in xrange(*i.indices(len(self)))]
else:
raise TypeError("Invalid argument")
That works well thanks, and then is it necessary to add the same requests to PRecordFactory? Or is it better to just call PriceTable at n intervals?
I had to add granularity to PriceTable otherwise it gave an error.
class PriceTable(object):
def __init__(self, instrument, granularity, reserve=10000):
self.instrument = instrument
self.granularity = granularity
self._dt = [None] * reserve # allocate space for datetime
self._o = [None] * reserve # allocate space for open values
self._h = [None] * reserve # allocate space for high values
self._l = [None] * reserve # allocate space for low values
self._c = [None] * reserve # allocate space for close/last values
self._v = [None] * reserve # allocate space for volume values
self._events = {} # registered events
self.idx = 0
Now it gives this error:
Traceback (most recent call last):
File "C:\User\Documents\Trading\OandaTrading\OandaV20\Testbot.py", line 648, in
you need to feed addItem also the other values that were added to the table, so: DATETIME/OPEN/HIGH/LOW/CLSE/VOLUME
Regarding the initialization part in the simplebot.py:
for crecord in rv['candles']:
if crecord['complete'] is True:
self.pt.addItem(crecord['time'],
# add the others here
float(crecord['mid']['c']),
int(crecord['volume']))
(or a quick test you could supply the close value for all the other values . Then you know how your code responds)
The PRecordFactory in the example does not provide these values. So you need to change this too. Options:
I've attempted to adapt the example as suggested, I'm able to request the data without error- but it gets returned as "None" for Open, High and Low. I'm assuming we're missing this input under def ParseTick(self, t):
if t["type"] == "PRICE":
#Need to add something here
self.data["c"] = (float(t['closeoutBid']) +
float(t['closeoutAsk'])) / 2.0
self.data["v"] += 1
return rec
The example has two parts: initialization and after that adding prices from the stream. The init thing is easy to adapt: just add the missing fields as I've pointed.
The prices from the stream is something else. A quick hack to get it work with OPEN/HIGH/LOW added just being a copy of the last:
if t["type"] == "PRICE":
self.data["c"] = (float(t['closeoutBid']) +
float(t['closeoutAsk'])) / 2.0
self.data["o"] = self.data["c"]
self.data["h"] = self.data["c"]
self.data["l"] = self.data["c"]
self.data["v"] += 1
But when you want the actual high and low for the timeframe you need to add additional logic to determine the values.
The simplebot .py was ment as an example. You can extend the example to your needs. If you need the OHLC records, please choose one of the options I gave you.
Further assistance to work to a specific solution is beyond the scope of the example, therefore I will close this issue now.
I have found another way to combat this, by bypassing PRecordFactory and calling PriceTable every minute (for M1 data):
starttime=time.time()
while True:
params = {"granularity": granularity,
"count": self.clargs.longMA}
r = instruments.InstrumentsCandles(instrument=instrument,
params=params)
rv = self.client.request(r)
for crecord in rv['candles']:
self.pt.addItem(crecord['time'],
float(crecord['mid']['o']),
float(crecord['mid']['h']),
float(crecord['mid']['l']),
float(crecord['mid']['c']),
int(crecord['volume']))
time.sleep(60.0 - ((time.time() - starttime) % 60.0))
you choose the 'retrieve candles from OANDA' option, which is fine. You probably get time drifting. Take a look at https://github.com/agronholm/apscheduler to tackle that if you need.
Is there a way to pull all candle data (Time, Open, High, Low , Close, Volume) using PriceTable? Or is the information limited to requesting only close and volume?