|
Attention! Read the forum rules carefully before posting a topic.
Try to find an answer in Wiki before asking a question. Submit programming questions in this forum only. Off topics are strictly forbidden.
Any topics which do not satisfy these rules will be deleted.
Problems with a very simple renko strategy |
echomary
|
Post subject: Problems with a very simple renko strategy |
Post rating: 0
|
Posted: Tue 19 Feb, 2013, 08:37
|
|
User rating: 0
Joined: Tue 23 Aug, 2011, 01:10 Posts: 7 Location: United States,
|
Very simple renko strategy: - Open an order with no stop loss or take profit after two renko bars of the same color are filled. - Close the order when a renko bar of the opposite color is filled. The strategy is described in this youtube tutorial: https://www.youtube.com/watch?v=vMCC9Ay5Cbw&t=28m18sHere's a key section of the strategy: public void onBar(Instrument instrument, OfferSide offerSide, PriceRange brickSize, IRenkoBar bar) { try { // debug code begin IChart chart = context.getChart(instrument); IChartObject line = chart.getChartObjectFactory().createVerticalLine("" + renkoCount++, bar.getEndTime()); line.setColor(isRedBar(bar)? Color.RED : Color.GREEN); chart.addToMainChart(line); log("-----------------------"); log(new Date(bar.getEndTime()).toGMTString()); log(new Date(history.getLastTick(instrument).getTime()).toGMTString()); // debug code end bars.addFirst(bar); if (bars.size() < 2) { return; } else if (bars.size() > 2) { bars.removeLast(); } if (!isActive(order)) { order = null; } else { if (isRedBar(bars.get(0)) != isRedBar(bars.get(1))) { order.close(); } return; } if (isRedBar(bars.get(0)) == isRedBar(bars.get(1))) { IEngine.OrderCommand orderCmd = !isRedBar(bars.get(0))? IEngine.OrderCommand.BUY : IEngine.OrderCommand.SELL; order = engine.submitOrder(getLabel(instrument), instrument, orderCmd, 0.1, 0.0, 0.0); } } catch (JFException e) { log(e.toString()); } } private boolean isRedBar(IRenkoBar bar) { return bar.getOpen() > bar.getLow(); }
In the above section of code, in the debug lines, why is it telling me that the last tick time is later than the end time of the bar passed to onBar? There are large multi-minute gaps between the end time of the bar passed to onBar and the last tick time - why is this? I would expect onBar to be called when the most current bar is filled, and that should happen at the time of the last tick, no? Here's a chart showing back testing results with just a week's worth of data, illustrating the problems. I don't understand why I'm getting these results. 
Attachments: |
RenkoStrat1.java [3.83 KiB]
Downloaded 359 times
|
DISCLAIMER: Dukascopy Bank SA's waiver of responsability - Documents, data or information available on
this webpage may be posted by third parties without Dukascopy Bank SA being obliged to make any control
on their content. Anyone accessing this webpage and downloading or otherwise making use of any document,
data or information found on this webpage shall do it on his/her own risks without any recourse against
Dukascopy Bank SA in relation thereto or for any consequences arising to him/her or any third party from
the use and/or reliance on any document, data or information found on this webpage.
|
|
|
|
|
 |
API Support
|
Post subject: Re: Problems with a very simple renko strategy |
Post rating: 0
|
Posted: Tue 19 Feb, 2013, 08:49
|
|
User rating: ∞
Joined: Fri 31 Aug, 2007, 09:17 Posts: 6139
|
echomary wrote: In the above section of code, in the debug lines, why is it telling me that the last tick time is later than the end time of the bar passed to onBar? There are large multi-minute gaps between the end time of the bar passed to onBar and the last tick time - why is this? I would expect onBar to be called when the most current bar is filled, and that should happen at the time of the last tick, no? See IStrategy.onBar description: https://www.dukascopy.com/wiki/#Strategy_API
|
|
|
|
 |
echomary
|
Post subject: Re: Problems with a very simple renko strategy |
Post rating: 0
|
Posted: Tue 19 Feb, 2013, 09:01
|
|
User rating: 0
Joined: Tue 23 Aug, 2011, 01:10 Posts: 7 Location: United States,
|
I was referring to the onBar method of the IRenkoBarFeedListener, not the onBar method of IStrategy. I don't see any documention for this on the page which you linked to.
|
|
|
|
 |
API Support
|
Post subject: Re: Problems with a very simple renko strategy |
Post rating: 0
|
Posted: Tue 19 Feb, 2013, 09:42
|
|
User rating: ∞
Joined: Fri 31 Aug, 2007, 09:17 Posts: 6139
|
The principle is the same - you receive the renko bar in the listeners onBar call back method once it is finished, thus in the onBar method, the last tick time might be already greater than the finished renko's end time. If you wish to retrieve the currently-forming renko bar then use IHistory.getRenkoBar with shift=0.
|
|
|
|
 |
echomary
|
Post subject: Re: Problems with a very simple renko strategy |
Post rating: 0
|
Posted: Tue 19 Feb, 2013, 11:05
|
|
User rating: 0
Joined: Tue 23 Aug, 2011, 01:10 Posts: 7 Location: United States,
|
To use IRenkoBarFeedListener in my strategy, I would need the onBar method to be invoked precisely when the current renko bar becomes fully filled and before any subsequent ticks arrive. Otherwise, the bar is essentially expired and my strategy is examing an old bar. The bar is filled when a tick arrives, so I don't understand why IRenkBarFeedListener.onBar isn't invoked then -- it seems like a useless method when it's invoked at a seemingly arbitrary time. I've rewritten my strategy and placed the key bits in IStrategy.onTick. It calls history.getRenkoBar with shift=0 and compares the open price of the bar with the bid price of the current tick, and then it does its thing when the difference in pips is the size of a renko bar. This seems like an unintuitive way of accomplishing the goal when there's an IRenkoBarFeedListener that could do the job if the onBar invocation was at the time of the last tick that filled the bar. Also I'm slightly perplexed why the renko bar passed to IRenkoBarFeedListener.onBar can return the same values for getOpen() and getClose(). I've heard other users describe this behavior as confusing as well, and I've seen no explanation that makes sense to me. If it's a bar in progress, I might expect open and close values to be the same, but more likely I would expect getClose() to return Double.NaN. For a filled renko bar, it seems logical that open and close would vary by the size of one renko bar, and high and low values would correspond with wicks. Here's results from the modified strategy. There may still some problems with it.  Here's the relevent section of code: public void onTick(Instrument instrument, ITick tick) throws JFException { if (!instrument.equals(this.instrument)) return; IRenkoBar renkoBar0 = history.getRenkoBar(instrument, OfferSide.BID, PriceRange.valueOf(renkoSize), 0); IRenkoBar renkoBar1 = history.getRenkoBar(instrument, OfferSide.BID, PriceRange.valueOf(renkoSize), 1); if (renkoBar0 == null) { return; } double pipDiff = toPips(instrument, renkoBar0.getOpen() - tick.getBid()); if (Math.abs(pipDiff) >= renkoSize) { if (!isActive(order)) { order = null; } else { if (isRedBar(renkoBar0) != isRedBar(renkoBar1)) { order.close(); } return; } if (isRedBar(renkoBar0) == isRedBar(renkoBar1)) { IEngine.OrderCommand orderCmd = !isRedBar(renkoBar0)? IEngine.OrderCommand.BUY : IEngine.OrderCommand.SELL; order = engine.submitOrder(getLabel(instrument), instrument, orderCmd, 0.1, 0.0, 0.0); } } }
Attachments: |
RenkoStrat1.java [3.2 KiB]
Downloaded 302 times
|
RenkoStrat1.java [3.44 KiB]
Downloaded 304 times
|
DISCLAIMER: Dukascopy Bank SA's waiver of responsability - Documents, data or information available on
this webpage may be posted by third parties without Dukascopy Bank SA being obliged to make any control
on their content. Anyone accessing this webpage and downloading or otherwise making use of any document,
data or information found on this webpage shall do it on his/her own risks without any recourse against
Dukascopy Bank SA in relation thereto or for any consequences arising to him/her or any third party from
the use and/or reliance on any document, data or information found on this webpage.
|
|
|
|
|
 |
API Support
|
Post subject: Re: Problems with a very simple renko strategy |
Post rating: 0
|
Posted: Tue 19 Feb, 2013, 14:15
|
|
User rating: ∞
Joined: Fri 31 Aug, 2007, 09:17 Posts: 6139
|
echomary wrote: To use IRenkoBarFeedListener in my strategy, I would need the onBar method to be invoked precisely when the current renko bar becomes fully filled and before any subsequent ticks arrive IRenkoBarFeedListener.onBar gets fired exactly when the last tick breaches its range, thus the last tick will never be within the last finished renko. echomary wrote: Also I'm slightly perplexed why the renko bar passed to IRenkoBarFeedListener.onBar can return the same values for getOpen() and getClose(). Then you have misunderstood the renko algorithm. For all the "spike" renko bricks the close and open prices match - it's easy to check this on a chart which has an OHLC info object on it.
|
|
|
|
 |
echomary
|
Post subject: Re: Problems with a very simple renko strategy |
Post rating: 0
|
Posted: Thu 21 Feb, 2013, 02:03
|
|
User rating: 0
Joined: Tue 23 Aug, 2011, 01:10 Posts: 7 Location: United States,
|
My code seems to be (mostly?) working now, but only after adding a couple tweaks which I don't fully understand why I need to add. Here's the key section of code: public void onBar(Instrument instrument, OfferSide offerSide, PriceRange brickSize, IRenkoBar renkoBar1) { if (!instrument.equals(this.instrument)) return; try { IRenkoBar renkoBar0 = history.getRenkoBar(instrument, OfferSide.BID, PriceRange.valueOf(renkoSize), 0); if (renkoBar0 == null) { return; } double pipDiff = toPips(instrument, history.getLastTick(instrument).getBid() - renkoBar0.getOpen()); if (Math.abs(pipDiff) >= renkoSize) { if (!isActive(order)) { order = null; } else { if (isRedBar(renkoBar0) != lastBarRed) { //isRedBar(renkoBar1)) { // debug code begin log("----------------------"); log("Closing order " + order.getLabel()); log("renkoBar0: " + renkoBar0.toString()); log("renkoBar1: " + renkoBar1.toString()); // debug code end order.close(); } lastBarRed = isRedBar(renkoBar0); return; } if (isRedBar(renkoBar0) == isRedBar(renkoBar1)) { IEngine.OrderCommand orderCmd = !isRedBar(renkoBar0)? IEngine.OrderCommand.BUY : IEngine.OrderCommand.SELL; order = engine.submitOrder(getLabel(instrument), instrument, orderCmd, 0.1, 0.0, 0.0); } lastBarRed = isRedBar(renkoBar0); } } catch (JFException e) { log(e.toString()); } }
private boolean isRedBar(IRenkoBar bar) { return bar.getOpen() > bar.getLow(); }
Take this line: if (isRedBar(renkoBar0) != lastBarRed) { //isRedBar(renkoBar1)) {
If I remove the lastBarRed variable and call isRedBar(renkoBar1) instead, I get this:  Quote: The principle is the same - you receive the renko bar in the listeners onBar call back method once it is finished, thus in the onBar method, the last tick time might be already greater than the finished renko's end time. If you wish to retrieve the currently-forming renko bar then use IHistory.getRenkoBar with shift=0.
So shouldn't the bar returned by history.getRenkoBar with shift=0 be at least one renko in size when IRenkoBarFeedListener.onBar is called? What exactly do you mean when you say "once it is finished"? I would think it's when the currently forming bar has met or exceeded the size of one renko that the previous bar is finished. I must not be understanding something. Why do I need to perform a check with the lines: double pipDiff = toPips(instrument, history.getLastTick(instrument).getBid() - renkoBar0.getOpen()); if (Math.abs(pipDiff) >= renkoSize) { ...
If I don't add these lines, I get:  With the tweaks added, I'm getting closer to the right results, but there still appears to be errors in the timing of entering and exiting some trades (the highlighted part is not an example of an error though - that's a section where i was getting wrong results before):  Subtracting a small fraction from the expected renkoSize seems to fix the occassionally seen problem of missing a bar that would close an open order (order 23-EURUSD22 to be specific): if (Math.abs(pipDiff) >= renkoSize - 0.001) { ...
That doesn't seem like the truly correct way of fixing the problem though. Is this a bug in the platform - shouldn't that be a blue bar?  Isn't this also a platform bug - shouldn't those two bars be consolidated into one bar?  Sorry to be so general, but is there a more correct way of writing this strategy?
Attachments: |
RenkoStrat2.java [4 KiB]
Downloaded 310 times
|
DISCLAIMER: Dukascopy Bank SA's waiver of responsability - Documents, data or information available on
this webpage may be posted by third parties without Dukascopy Bank SA being obliged to make any control
on their content. Anyone accessing this webpage and downloading or otherwise making use of any document,
data or information found on this webpage shall do it on his/her own risks without any recourse against
Dukascopy Bank SA in relation thereto or for any consequences arising to him/her or any third party from
the use and/or reliance on any document, data or information found on this webpage.
|
|
|
|
|
 |
API Support
|
 |
Post subject: Re: Problems with a very simple renko strategy |
Post rating: 0
|
Posted: Fri 22 Feb, 2013, 13:00
|
|
User rating: ∞
Joined: Fri 31 Aug, 2007, 09:17 Posts: 6139
|
echomary wrote: If I remove the lastBarRed variable and call isRedBar(renkoBar1) instead, I get this:  What do you find being wrong there? The renkoBar0 is null-brick, as there are no ticks within its range. echomary wrote: So shouldn't the bar returned by history.getRenkoBar with shift=0 be at least one renko in size when IRenkoBarFeedListener.onBar is called? What do you mean by "least one renko in size"? If you mean tick, then a renko brick can also contain 0 ticks, if there are no ticks within its range, say one tick is at 1.3001 and the next 1.3101 then the listener will receive 4 renko bricks in a row: - 1.3000 - 1.3025 (includes tick 1.3001)
- 1.3025 - 1.3050 (empty: endTime - startTime = 1ms)
- 1.3050 - 1.3075 (empty: endTime - startTime = 1ms)
- 1.3075 - 1.3100 (empty: endTime - startTime = 1ms)
and the currently forming renko bar will include the tick with price 1.3101. echomary wrote: Sorry to be so general, but is there a more correct way of writing this strategy? From api standpoint, working with IFeedListener gives you more flexibility in switching between different feeds and feed types, see: https://www.dukascopy.com/wiki/#Chart_feeds/Subscribe_to_a_feedFrom business logic standpoint, you just need to make sure that your assumptions about the renko-generation logic are correct. Quote: Is this a bug in the platform - shouldn't that be a blue bar?  Isn't this also a platform bug - shouldn't those two bars be consolidated into one bar?  This is under investigation.
|
|
|
|
 |
echomary
|
Post subject: Re: Problems with a very simple renko strategy |
Post rating: 0
|
Posted: Sat 23 Feb, 2013, 07:12
|
|
User rating: 0
Joined: Tue 23 Aug, 2011, 01:10 Posts: 7 Location: United States,
|
Quote: What do you find being wrong there? The renkoBar0 is null-brick, as there are no ticks within its range. Zooming in on a one min chart, I see now that there's a gap in the price that was created over a weekend. For renkoBar1, the open price is 1.23962, whereas all the other open prices are even renko values (divisible by 25 pips). This makes sense though - I just wasn't accounting for gaps.  I think this is the fix: public void onBar(Instrument instrument, OfferSide offerSide, PriceRange brickSize, IRenkoBar renkoBar1) { if (!instrument.equals(this.instrument)) return; try { IRenkoBar renkoBar0 = history.getRenkoBar(instrument, OfferSide.BID, PriceRange.valueOf(renkoSize), 0); if (isFirstBarOfWeek(renkoBar0)) { return; } if (isFirstBarOfWeek(renkoBar1)) { renkoBar1 = history.getRenkoBars(instrument, OfferSide.BID, PriceRange.valueOf(renkoSize), 2, renkoBar1.getTime(), 0).get(0); } if (!isActive(order)) { order = null; } else { if (isRedBar(renkoBar0) != isRedBar(renkoBar1)) { order.close(); } return; } if (isRedBar(renkoBar0) == isRedBar(renkoBar1)) { IEngine.OrderCommand orderCmd = !isRedBar(renkoBar0)? IEngine.OrderCommand.BUY : IEngine.OrderCommand.SELL; order = engine.submitOrder(getLabel(instrument), instrument, orderCmd, 0.1, 0.0, 0.0); } } catch (JFException e) { log(e.toString()); } } private boolean isFirstBarOfWeek(IRenkoBar renkoBar) throws JFException { IRenkoBar previousBar = history.getRenkoBars(instrument, OfferSide.BID, PriceRange.valueOf(renkoSize), 2, renkoBar.getTime(), 0).get(0); Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); cal.setTime(new Date(renkoBar.getTime())); return cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY && cal.get(Calendar.HOUR_OF_DAY) == 21 && cal.get(Calendar.MINUTE) == 0 && renkoBar.getOpen() != previousBar.getClose(); }
Oddly, incidentally, the strategy seems to work infinitely better (on last year of EUR/USD) with trend detection reversed, replacing IEngine.OrderCommand orderCmd = !isRedBar(renkoBar0)? IEngine.OrderCommand.BUY : IEngine.OrderCommand.SELL;
with IEngine.OrderCommand orderCmd = isRedBar(renkoBar0)? IEngine.OrderCommand.BUY : IEngine.OrderCommand.SELL;
Thanks for your assistance.
Attachments: |
RenkoStrat1.java [4.03 KiB]
Downloaded 375 times
|
DISCLAIMER: Dukascopy Bank SA's waiver of responsability - Documents, data or information available on
this webpage may be posted by third parties without Dukascopy Bank SA being obliged to make any control
on their content. Anyone accessing this webpage and downloading or otherwise making use of any document,
data or information found on this webpage shall do it on his/her own risks without any recourse against
Dukascopy Bank SA in relation thereto or for any consequences arising to him/her or any third party from
the use and/or reliance on any document, data or information found on this webpage.
|
|
|
|
|
 |
|
Pages: [
1
]
|
|
|
|
|