Here's the code I previously posted to do exactly that:
bigdavediode
@bigdavediode
Posts made by bigdavediode
-
RE: ThinkorSwim Imp_Vol Function
-
RE: Help with Volume-Weigthed Moving Average (VWMA) indicator needed
I don't have example code to do that in this particular case because I don't reset the VWAP each day, I just use a running tally.
You may wish to consult this thread which will show you that getting datetimes in an indicator can be a challenge: https://community.backtrader.com/topic/489/getting-the-current-date-in-a-strategy-s-next-method/2
I have done it (iirc) by passing the datafeed separately into the indicator as datas[0] and the line that I'm operating the indicator on as datas[1].
So in my indicator I can filter (or in your case you can reset the VWAP) within the indicator based on the date:
curdt = self.datas[0].datetime.date(ago=0)
curtm = self.datas[0].datetime.time(ago=0)And my line calculation input is in datas[1]. And I call passing both the data line and the input line that I'm working on:
x = DistPercentileSampled(d, self.inds[d]['highdiffs'], period=780, raw=True, bar_size=30, matchwkdy=False, inputdesc='SELL_disthighdiffs', subplot = False)
d is datas[0] and self.inds[d]['highdiffs'] is datas[1] within the indicator.
-
RE: Help with Volume-Weigthed Moving Average (VWMA) indicator needed
@Armaan-Syed This routine doesn't reset at the start of a trading day and continuously adjusts based on whatever period you supply. If you wish to have it reset at the start of each day you would need to access the datetime in the indicator, which might be problematic. An easier solution might just be to change typprice and cumtypprice to lines and just calculate a temporary daily running volume.
Or I suppose you could pass the data feed itself along with the actual data line to the indicator so you can recover the datetime information from the feed within your indicator to reset your running daily volume calculation at the start of day. I've passed those that way in the past with several indicators.
Having said that, I suggest that a running daily VWAP is more useful than one that resets daily. But I'm open to arguments.
-
RE: ZigZag based on Close Prices
@Martin-Bouhier said in ZigZag based on Close Prices:
Input("Reversal",0,100,5);
Hi Martin, I would suspect that you're either not using the same input data (ie. a moving average or smoother that is smaller and finer in the Metastock formula) or that the "percentage" input involves specifying a retracement perhaps before it counts as a peak or valley in that zig zag routine. Also I'm curious to know what the 5 in the "reversal" params specifies.
I don't like that python version. If there are repeated values at a peak, for example such as 200, 201, 201, 199, then it's possible for the code to entirely miss a peak.
Good luck.
-
RE: Hyper Fast Lines Based Zig Zag Indicator 3
Fixed a real time bar delay bug and tightened the code:
def __init__(self): cpy = copy.copy(self.data) tmp = bt.If(self.data(0) == self.data(-1), cpy(-1) + 0.000001, self.data(0)) self.lines.zigzag_peak = bt.If(bt.And(tmp(-1)>tmp(-2), tmp(-1)>tmp(0)), self.data(-1), float('nan')) cpy = copy.copy(self.data) tmp = bt.If(self.data(0) == self.data(-1), cpy(-1) - 0.000001, self.data(0)) self.lines.zigzag_valley = bt.If(bt.And(tmp(-1) < tmp(-2), tmp(-1) < tmp(0)), self.data(-1), float('nan')) self.lines.zigzag = bt.If(self.zigzag_peak, self.zigzag_peak, bt.If(self.zigzag_valley, self.zigzag_valley, float('nan')))
-
RE: Hyper Fast Lines Based Zig Zag Indicator 3
Just to mention if you're attempting to use this live it obviously looks ahead one bar into the future which isn't allowed. If you're using it for preloaded historical data in a batch it works for identifying the exact turning point rather than one bar late. But for live data you'll need to move it one bar back by subtracting one from every bar reference as below. I added a couple of del lines just to prompt a bit of memory cleanup but they are entirely optional.
And yeah, I should use camelcase for the class name. Added a couple of comments to help with anyone who wants to understand the code.
def __init__(self): #Make a copy tmp = copy.copy(self.data) #Peak shift tmp = bt.If(self.data(-1) == self.data(-2), tmp(-2) + 0.000001, self.data(-1)) #Find peaks self.zigzag_peak = bt.If(bt.And(tmp(-1)>tmp(-2), tmp(-1)>tmp(0)), self.data(-1), float('nan')) del tmp tmp = copy.copy(self.data) #valley shift tmp = bt.If(self.data(-1) == self.data(-2), tmp(-2) - 0.000001, self.data(-1)) #Find valleys: self.zigzag_valley = bt.If(bt.And(tmp(-1) < tmp(-2), tmp(-1) < tmp(0)), self.data(-1), float('nan')) self.lines.zigzag = bt.If(self.zigzag_peak, self.zigzag_peak, bt.If(self.zigzag_valley, self.zigzag_valley, float('nan'))) self.lines.zigzag_peak = self.zigzag_peak * (1 + self.p.plotdistance) self.lines.zigzag_valley = self.zigzag_valley * (1 - self.p.plotdistance) del tmp
-
RE: Hyper Fast Lines Based Zig Zag Indicator 3
I realize this chart isn't the best illustration as the SMA wiggles and results in some doubling up of peak/valley indications which makes it difficult to see if it's showing a high or low at points.
-
RE: oandav20 resampling from 15m to 4h shows extra bars.
Use compression, as above, compression 1 for 1 minute bars if you wish, as below:
timeframe=bt.TimeFrame.Minutes, compression=barsize, useRTH=False, #outsideRth=True, fill orders outside rth -- use for orders, not here... sessionstart=datetime.time(9, 30, 0), sessionend=datetime.time(16, 30, 0),
...and then your adddata or resample line using these arguments.
-
RE: Hyper Fast Lines Based Zig Zag Indicator 3
And a screenshot with it used on an SMA:
-
Hyper Fast Lines Based Zig Zag Indicator 3
Hi,
Peak valley detection is an indicator that appears simple and isn't. This is my third zig zag indicator optimized to be lines-based in an init rather than step-by-step in a next() or once. It is blindingly fast.
I'd be interested in hearing if anyone can detect any bugs. Please note that the zigzag line will be the unaltered turning points, but zigzag_peak and zigzag_valley are altered by the param plotdistance to move them away from the underlying data for visualization purposes.
I've gotten it down to seven lines, not quite half my previous attempt. The extra two lines are for display purposes.
If anyone can beat this for speed or efficiency I'd be very open to seeing what you can do.
''' Author: B. Bradford MIT License Copyright (c) 2020 B. Bradford Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ''' import backtrader as bt import copy class bbzigzag(bt.Indicator): plotinfo = dict(subplot=True, zigzag=dict(_name='zigzag', color='darkblue', ls='--', _skipnan=True), ) plotlines = dict( zigzag_peak=dict(marker='v', markersize=7.0, color='red', fillstyle='full', ls=''), zigzag_valley=dict(marker='^', markersize=7.0, color='red', fillstyle='full', ls=''), #zigzag=dict(_name='zigzag', color='red', ls='--', _skipnan=True), ) params = ( ('plotdistance', 0.03), # distance to plot arrows (alters high/low indicator lines but not zigzag line) ) lines = ('zigzag', 'zigzag_peak', 'zigzag_valley',) def __init__(self): tmp = copy.copy(self.data) tmp = bt.If(self.data(0) == self.data(-1), tmp(-1) + 0.000001, self.data(0)) self.zigzag_peak = bt.If(bt.And(tmp(0)>tmp(-1), tmp(0)>tmp(1)), self.data(0), float('nan')) tmp = copy.copy(self.data) tmp = bt.If(self.data(0) == self.data(-1), tmp(-1) - 0.000001, self.data(0)) self.zigzag_valley = bt.If(bt.And(tmp(0) < tmp(-1), tmp(0) < tmp(1)), self.data(0), float('nan')) self.lines.zigzag = bt.If(self.zigzag_peak, self.zigzag_peak, bt.If(self.zigzag_valley, self.zigzag_valley, float('nan'))) self.lines.zigzag_peak = self.zigzag_peak * (1 + self.p.plotdistance) self.lines.zigzag_valley = self.zigzag_valley * (1 - self.p.plotdistance)
This is also profoundly easy to change -- for example to allow it to ignore small retracements simply change the params section to:
params = ( ('up_retrace', 0.0), # 0.02 ('dn_retrace', 0.0), # 0.02 ('plotdistance', 0.03), # distance to plot arrows (alters high/low indicator lines but not zigzag line)
And change the tmpline from detecting equal bar entries to a range of bar entries to accommodate each retracement amount.