Math::Business::DMI

80 views
Skip to first unread message

BobBack

unread,
Sep 14, 2010, 6:09:46 AM9/14/10
to stockmonkey
I'm having issues with supplying data to this function.
On the CPAN module page http://search.cpan.org/~jettero/stockmonkey-2.9013/Business/DMI.pm
the example suggests the following order for data:-

<code>
my @data_points = (
[ 5, 3, 4 ], # high, low, close
[ 6, 4, 5 ],
[ 5, 4, 4.5 ],
);
</code>

However using the following data:-

<code>
@dmiData = (
[ 168, 166, 167 ],
[ 168, 166, 168 ],
[ 168, 166, 168 ],
[ 168, 166, 168 ],
);
</code>

dies with the following error.

Illegal division by zero at .../Math/Business/DMI.pm line 122.

Changing the order to [high, close, low] completes without error, and
the values look impressive on a graph, but I have no idea if they are
valid.

As I write I'm wondering if this could be related to some way Perl
handles numeric values i.e. 168 might be evaluated as
167.99999999999999999, but surely this would be the same for ALL data
values of 168?

Additionally I'm unsure of how many sets of high/low/close data to
use. It would be convenient to use between 12 and 20 but I wonder
should it be a multiple of say 2, 3 or 4?

Any information most gratefully received!

Finally, warm thanks to Paul Miller for implementing these functions
in Perl.

Paul Miller

unread,
Sep 14, 2010, 6:41:51 AM9/14/10
to stockmonkey


On Sep 14, 6:09 am, BobBack <drchap...@gmail.com> wrote:
> I'm having issues with supplying data to this function.

We'll figure it out.

>       [ 5, 3, 4 ], # high, low, close

Yes, this is right.

> <code>
> @dmiData = (
>     [ 168, 166, 167 ],
>     [ 168, 166, 168 ],
>     [ 168, 166, 168 ],
>     [ 168, 166, 168 ],
>     );
> </code>
> Illegal division by zero at .../Math/Business/DMI.pm line 122.

http://github.com/jettero/stockmonkey/blob/master/t/06_bobback_dmi.t

Works for me... I need to see more of your code.

> Changing the order to [high, close, low] completes without error, and

I checked and high, low, close is the correct ordering:

http://github.com/jettero/stockmonkey/blob/master/Business/DMI.pm#L51

> Finally, warm thanks to Paul Miller for implementing these functions
> in Perl.

Thanks for enjoying it. That was entirely the point!

-Paul

BobBack

unread,
Sep 14, 2010, 1:52:07 PM9/14/10
to stockmonkey
Thank you Paul for your very prompt reply.

> Works for me... I need to see more of your code.

And the example you posted evaluates for me also. I think that clearly
exonerates your module from any blame. My code is another matter.
For curiosity I'll post a snippet of my code. As the whole script is
around 47kB this is just a snip, and it's entirely possible the error
is elsewhere.

<code>
#!/usr/bin/perl -w

use Math::Business::DMI;

#declarations
my $dmi = Math::Business::DMI->recommended;
my (
@dmiData,
@dmiDataSlice,
$adx,
$pdi,
$mdi,
);

#part of main loop
@dmiDataSlice = (
priceToTick($data->{$selectionId}->{'B1'}->{'price'}),
priceToTick($data->{$selectionId}->{'L1'}->{'price'}),
priceToTick($data->{$selectionId}->{'runner'}-
>{'lastPriceMatched'}),
);

push (@dmiData, [@dmiDataSlice]);
if ( scalar (@dmiData) >5) {
shift @dmiData;
}

print "@dmiDataSlice\n"; # debug to check the input data

$dmi->insert( @dmiData );
($pdi, $mdi, $adx) = $dmi->query;

#loop
</code>
The whole script features a loop which reads prices twice a second and
places trades depending on position. I intended to add in the DMI
module to indicate a strong position, either buy or sell.
The priceToTick function returns an integer

This snippet is supposed to push new data onto the @dmiData array and
shift old data off it.
I have managed to get it to run without dying by changing the '5' to
'4' in the following line:

if ( scalar (@dmiData) >5) {

but as to why I'm currently none the wiser! I suspect it's probably
inexperience with Perl in general, and referencing/dereferencing
arrays in particular.

Paul Miller

unread,
Sep 15, 2010, 7:06:06 AM9/15/10
to stockmonkey

Nothing really jumps out at me regarding why the thing fails... But I
have some ideas regarding where to start looking.
Try Data::Dumper, to make sure what you're feeding to insert really is
what you mean to feed to insert:

warn "Just checking: " . Dumper(\@dmiData); sleep 1;

On Sep 14, 1:52 pm, BobBack <drchap...@gmail.com> wrote:
>         push (@dmiData, [@dmiDataSlice]);
>         if ( scalar (@dmiData) >5) {
>                 shift @dmiData;
>         }

This doesn't seem right to me either. The ::DMI object already does
this type of shifting internally. You would normally feed each
datapoint to it one at a time (or all at once) but I think you're
feeding a lot of the same data points over and over — I could be wrong
though, I don't have a clear understanding of your mainloop.

This is the intended paradigm:

while( my ($high, $low, $close) = $sth->fetchrow_array ) {

$dmi->insert([ $high, $low, $close ]);

}

If you're only concerned with a 5-day moving computation, then
$dmiObject->set_days(5) ... although Wilder suggested 14 was the magic
number (for whatever reason).

-Paul

BobBack

unread,
Sep 16, 2010, 8:06:09 PM9/16/10
to stockmonkey
Thank you for your interest and suggestions Paul.
Perhaps I should explain in further detail what I have done and what I
am trying to do.

I have tried Data::Dumper to display the contents of both @dmiData and
@dmiDataSlice as the loop runs.
Before dying feeding @dmiData to Data::Dumper returns:
<code>
$VAR1 = [
[
168,
166,
167
],
[
168,
166,
168
],
[
168,
166,
168
],
[
168,
166,
168
]
</code>

The main loop intentionally reads live market data approximately twice
a second, so understandably data may be unchanged from the previous
iteration.
As a further example my current script also uses your excellent
Math::Business::BollingerBands.
I use this in the following way.
I initialise this module using:
<code>
my $bb = Math::Business::BollingerBands->recommended;
</code>
I feed this an array of the last 22 closing prices constructed by
pushing the latest price onto the array, and if the array is greater
than 22 items, shifting the oldest price off the array.
(the value of 22 was determined through repeated running of cached
data to provide the most profitable graph for my trigger parameters -
so many variables!)
This 22 item array is then passed to the BollingerBands object:
<code>
$bb->insert( @lastPriceMatched )
</code>
Now from reading your reply I wonder if I'm making it hard for myself
(and your modules) by throwing them an array of 22 prices, which all
but 1 will have been passed previously, albeit shifted by 1 place.
To summarise, I have serial live market data @ 2Hz approx. and I want
to get the most accurate calculation possible in 1/10 second. Should I
just pass the latest value or the last 20 values to get an accurate
calculation? Does this also vary from different maths modules?
Once again thank you for your patience and help.

Kind Regards,

Bob

Paul Miller

unread,
Sep 16, 2010, 8:46:54 PM9/16/10
to stockmonkey

> Now from reading your reply I wonder if I'm making it hard for myself
> (and your modules) by throwing them an array of 22 prices, which all
> but 1 will have been passed previously, albeit shifted by 1 place.
> To summarise, I have serial live market data @ 2Hz approx. and I want
> to get the most accurate calculation possible in 1/10 second. Should I
> just pass the latest value or the last 20 values to get an accurate
> calculation? Does this also vary from different maths modules?
> Once again thank you for your patience and help.


Well, they're designed to take the next one and the next one and the
next one... that's why it's called insert() and not set(). In fact,
its going to be *wrong* if you're feeding it the same data over and
over and over. The only thing you'd want to feed it is the *new*
data, never the same numbers over and over. It does the shifting for
you internally, and efficiently.

What you're doing would work better like this:

while( whatever ) {
my ($PDI, $MDI, $ADX) = Math::Business::DMI->new->insert(@data)-
>query;
}

This throws away all the intnernal moving data computational ability,
and you'll be doing the same heaving lifting on every iteration, but
it's going to work better than what you're doing (I think).

The way *I* would approach it would be to feed it only new data (only)
when it comes in.

while( whatever ) {
if( @new_points = check_for_new_data(whatever) ) {

$dmi->insert( @new_points );
# new data, never old data
# the old data is already in there, re-adding
# the old data is going to give you some other
# calculation, who knows what

BobBack

unread,
Sep 17, 2010, 3:44:13 PM9/17/10
to stockmonkey
Thank you Paul,

> Well, they're designed to take the next one and the next one and the
> next one... that's why it's called insert() and not set().  In fact,

Mea Culpa. I really can't believe I didn't pick this up... INSERT. Now
I'm passing the single last traded value the
Math::Business::BollingerBands and Math::Business::RSI are different
beasts altogether.

However, I'm still having issues with Math::Business::DMI.
It seems to have a problem with the 15th tuple I insert.
Below is a listing of Data::Dumper output on @dmiData which I $dmi-
>insert(@dmiData). The initial integer is just a printout counter.
1$VAR1 = [
168,
167,
167
];

2$VAR1 = [
168,
167,
167
];

3$VAR1 = [
168,
167,
167
];

4$VAR1 = [
168,
167,
168
];

5$VAR1 = [
168,
167,
168
];

6$VAR1 = [
168,
167,
168
];

7$VAR1 = [
168,
167,
168
];

8$VAR1 = [
168,
167,
168
];

9$VAR1 = [
168,
167,
168
];

10$VAR1 = [
168,
167,
168
];

11$VAR1 = [
168,
167,
168
];

12$VAR1 = [
168,
167,
167
];

13$VAR1 = [
168,
167,
167
];

14$VAR1 = [
168,
167,
167
];

15$VAR1 = [
168,
167,
167
];
I call $dmi->insert(@dmiData) with one tuple as above. As mentioned
before, there are repeated values simply because the market hasn't
changed since the last polling. All I can think of is that the
internal calculations expect some natural deviation in the input data.
The other
solution I could try is not to insert values unless they have changed.

> The way *I* would approach it would be to feed it only new data (only)
> when it comes in.

Once again that's exactly what I wanted! Believe it or not english is
my native language... INSERT - Damn. Thanks for all your patience.

Kind regards,

Bob

Paul Miller

unread,
Sep 17, 2010, 3:59:41 PM9/17/10
to stockmonkey


On Sep 17, 3:44 pm, BobBack <drchap...@gmail.com> wrote:
> $dmi->insert(@dmiData). The initial integer is just a printout counter.
>
> 1$VAR1 = [
>           168,
>           167,
>           167
>         ];

If @dmiData contains []'s, I expect this to look like this:

$VAR1 = [[ 168,167,167 ]];

Are you doing Dumper(\@dmiData); ? or Dumper(@dmiData)?





> internal calculations expect some natural deviation in the input data.

Yes, I believe they do, lemme make a test for this.

> Once again that's exactly what I wanted! Believe it or not english is
> my native language... INSERT - Damn. Thanks for all your patience.

I frequently remind people I'm a native English speaker, so maybe we
should make a club.

Paul Miller

unread,
Sep 17, 2010, 4:35:46 PM9/17/10
to stockmonkey
> there are repeated values simply because the market hasn't changed since the last polling.

I believe Wilder would have us 0 out the DX when the DI is 0. Not
really sure. I do have a copy of his book now, but I'm unlikely to
look it up as it seems clear enough.

-Paul

I pushed 2.9014 to the CPAN, but if you're in a hurry, it's also here:

http://jettero.pl/perl/stockmonkey-2.9014.tar.gz

Paul Miller

unread,
Sep 17, 2010, 4:37:44 PM9/17/10
to stockmonkey


On Sep 17, 4:35 pm, Paul Miller <jett...@gmail.com> wrote:
> I believe Wilder would have us 0 out the DX when the DI is 0.

That was kindof cryptic and possibly an internal monolog...

I mean this:

http://github.com/jettero/stockmonkey/commit/2d251aed38b0f42bbfe2a89aef9168c62633dfcc#L0R91

BobBack

unread,
Sep 27, 2010, 2:19:17 PM9/27/10
to stockmonkey
My apologies for the delay in replying. Unfortunately the day job
takes precedence, a familiar tale for all I'm sure.

> Are you doing Dumper(\@dmiData); ? or Dumper(@dmiData)?

I was actually doing Dumper(@dmiData)

> Yes, I believe they do, lemme make a test for this.

I've just downloaded and installed stockmonkey-2.9014. It's running as
I write, with some particularly static trading values as fodder, and
seems absolutely happy. Grateful thanks for looking over it.

> I frequently remind people I'm a native English speaker, so maybe we
> should make a club.

Completely off topic so further apologies in advance...
I've always made good-natured fun of Americans (in the vein of John
Cleese) and working in construction one of my favourite points was the
aluminium/aluminum debate. It turns out we're both wrong but they're
closer to the original. http://en.wikipedia.org/wiki/Aluminium#Etymology
Reply all
Reply to author
Forward
0 new messages