This is a great example. Tyhanks for sharing. How would one goes about adding he number of Ticks that were aggregated in a bar (e.g Tickcount), Is it just a matter of creating a Volume column =1 at tick level? What should I do however if I also have Volume in my data and I want to have both information (for instance to get the average volume per Bid in a bar)?
One last question on this, as mentionned, I did use a csv file with the exact same column structure as in your example (columns=[bid, ask, datetime in last position]). The original file however come with the following structure [symbol, datetime, bid, ask] as show here:
Thus modifing the BidAskCSV class:
linesoverride = True # discard usual OHLC structure
# datetime must be present and last
lines = ('PAIR','datetime','bid', 'ask')
# datetime (always 1st) and then the desired order for
params = (
('PAIR', 0), # inherited from parent class
('datetime', 1), # inherited from parent class
('bid', 2), # default field pos 1
('ask', 3) # default field pos 2
The above won't work due to lines = ('PAIR','datetime','bid', 'ask') however replacing the section below instead is not returning an error message and so seems to be working fine:
lines = ('datetime','bid', 'ask')
I understand that the field 'PAIR' being a string is what is causing the error (code section below from -loadline), thus my questions:
What is the underlying rationale ? Is it because "lines" should only refers to preset categories defined in BT (datetime, OHLV, volume, etc...)?
What is the impact of simply not mentioning "PAIR" in the "lines" list (if any)?
for linefield in (x for x in self.getlinealiases() if x != 'datetime'):
# Get the index created from the passed params
csvidx = getattr(self.params, linefield)
if csvidx is None or csvidx < 0:
# the field will not be present, assignt the "nullvalue"
csvfield = self.p.nullvalue
# get it from the token
csvfield = linetokens[csvidx]
if csvfield == '':
# if empty ... assign the "nullvalue"
csvfield = self.p.nullvalue
# get the corresponding line reference and set the value
line = getattr(self.lines, linefield)
line = float(float(csvfield))# Why is the expectation to ALWAYS have a float - can it be changed for more flexibility? (cg 'PAIR' filed in TruFX import - Error message
The included filters are here: Docs - Filter Reference
They are available in the backtrader.filters module
If you want the one from the blog post, you can simply copy the code and use in your own development.
In this blog post, the described data feed is for the exported CSV data files or for direct usage of the binary (.fd or .min) which are of course static
For a real-time feed and trading broker for VisualChart you may want to look into:
Docs - Live Data Feeds and Live Trading / VisualChart
Blog - VisualChart Live Data/Trading
In the blog post introducing the feature you can see orders that were sent to VisualChart over the COM interface.
To take into account:
Test a lot. The code may contain bugs, your code may contain bugs and even VisualChart may contain bugs.
You need the python comtypes packaged detailed in the documentation. The Pull-Request hasn't yet been integrated into the main development tree (which seems more or less stopped from a development point of view)
Suggestion: read the Docs - Quickstart Access an comparison is done several times with a Simple Moving Average
You store the created indicator in a variable: self.myvar = bt.ind.Trix(...)
You access the values: self.myvar which automates the process of doing self.myvar.lines.trix