App-financeta

 view release on metacpan or  search on metacpan

lib/App/financeta/gui.pm  view on Meta::CPAN

    $log->debug("Using term $term");
    my $pwin = $win->{plot} || gpwin($term, size => [1024, 768, 'px']);
    $win->{plot} = $pwin;
    $symbol = $self->current->{symbol} unless defined $symbol;
    $type = $self->current->{plot_type} unless defined $type;
    my @general_plot = ();
    my @volume_plot = ();
    my @addon_plot = ();
    my @candle_plot = ();
    $self->indicator->color_idx(0); # reset color index
    if (defined $indicators and scalar @$indicators) {
        # ok now create a list of indicators to plot
        foreach (@$indicators) {
            my $iref = $_->{indicator};
            my $idata = $_->{data};
            my $iplot = $self->indicator->get_plot_args($data(,(0)), $idata, $iref);
            next unless $iplot;
            if (ref $iplot eq 'ARRAY') {
                push @general_plot, @$iplot if scalar @$iplot;
            } elsif (ref $iplot eq 'HASH') {
                my $iplot_gen = $iplot->{general};
                push @general_plot, @$iplot_gen if $iplot_gen and scalar @$iplot_gen;
                my $iplot_vol = $iplot->{volume};
                push @volume_plot, @$iplot_vol if $iplot_vol and scalar @$iplot_vol;
                my $iplot_addon = $iplot->{additional};
                push @addon_plot, @$iplot_addon if $iplot_addon and scalar @$iplot_addon;
                my $iplot_cdl = $iplot->{candle};
                push @candle_plot, @$iplot_cdl if $iplot_cdl and scalar @$iplot_cdl;
            } else {
                $log->warn('Unable to handle plot arguments in ' . ref($iplot) . ' form!');
            }
        }
    }
    if (defined $buysell and ref $buysell eq 'HASH' and
        defined $buysell->{buys} and defined $buysell->{sells}) {
        my $buys = $buysell->{buys};
        my $sells = $buysell->{sells};
        my $rtpnl = $buysell->{rtpnl};
        if (ref $buys eq 'PDL' and ref $sells eq 'PDL') {
            my $bsplot = $self->indicator->get_plot_args_buysell(
                $data(,(0)), $buys, $sells, $rtpnl);
            if (defined $bsplot and ref $bsplot eq 'ARRAY') {
                push @general_plot, @$bsplot if scalar @$bsplot;
            } elsif (ref $bsplot eq 'HASH') {
                my $bsplot_gen = $bsplot->{general};
                if ($bsplot_gen) {
                    push @general_plot, @$bsplot_gen if scalar @$bsplot_gen;
                }
                my $bsplot_addon = $bsplot->{additional};
                if (ref $bsplot_addon eq 'ARRAY' and scalar (@$bsplot_addon)) {
                    push @addon_plot, @$bsplot_addon;
                }
            }
        } else {
            $log->warn("Unable to plot invalid buy-sell data");
        }
    }
    $pwin->reset();
    # use multiplot
    $pwin->multiplot();
    my %binmode = ();
    if ($^O !~ /Win32/ and $Alien::Gnuplot::version < 4.6) {
        $log->debug("Binary mode is set to 0 due to gnuplot $Alien::Gnuplot::version");
        $binmode{binary} = 0;
    }
    if ($type eq 'OHLC') {
        my %addon_gen = ();
        if (@addon_plot) {
            $addon_gen{size} = ["1, 0.7"];
            $addon_gen{origin} = [0, 0.3];
            $addon_gen{bmargin} = 0;
            $addon_gen{lmargin} = 9;
            $addon_gen{rmargin} = 2;
        }
        $pwin->plot({
                %binmode,
                object => '1 rectangle from screen 0,0 to screen 1,1 fillcolor rgb "black" behind',
                title => ["$symbol Open-High-Low-Close", textcolor => 'rgb "white"'],
                key => ['on', 'outside', textcolor => 'rgb "yellow"'],
                border => 'linecolor rgbcolor "white"',
                xlabel => ['Date', textcolor => 'rgb "yellow"'],
                ylabel => ['Price', textcolor => 'rgb "yellow"'],
                xdata => 'time',
                xtics => {format => '%Y-%m-%d', rotate => -90, textcolor => 'orange', },
                ytics => {textcolor => 'orange'},
                label => [1, $self->brand, textcolor => 'rgb "cyan"', at => "graph 0.90,0.03"],
                %addon_gen,
            },
            {
                with => 'financebars',
                linecolor => 'white',
                legend => 'Price',
            },
            $data(,(0)), $data(,(1)), $data(,(2)), $data(,(3)), $data(,(4)),
            @general_plot,
        );
        if (@addon_plot) {
            $pwin->plot({
                    %binmode,
                    object => '1',
                    title => '',
                    key => ['on', 'outside', textcolor => 'rgb "yellow"'],
                    border => 'linecolor rgbcolor "white"',
                    ylabel => '',
                    xlabel => '',
                    xtics => '',
                    ytics => {textcolor => 'orange'},
                    bmargin => 0,
                    tmargin => 0,
                    lmargin => 9,
                    rmargin => 2,
                    size => ["1,0.3"], #bug in P:G:G
                    origin => [0, 0],
                    label => [1, "", at => "graph 0.90,0.03"],
                },
                @addon_plot,
            );
        }
    } elsif ($type eq 'OHLCV') {
        my %addon_gen = ();
        my %addon_vol = ();
        if (@addon_plot) {
            $addon_gen{size} = ["1, 0.6"]; #bug in P:G:G
            $addon_gen{origin} = [0, 0.4];
            $addon_vol{size} = ["1, 0.2"]; #bug in P:G:G
            $addon_vol{origin} = [0, 0];
        } else {
            $addon_gen{size} = ["1, 0.7"]; #bug in P:G:G
            $addon_gen{origin} = [0, 0.3];
            $addon_vol{size} = ["1, 0.3"]; #bug in P:G:G
            $addon_vol{origin} = [0, 0];
            $addon_vol{object} = '1'; # needed as otherwise the addon plot does it
        }
        $pwin->plot({
                %binmode,
                object => '1 rectangle from screen 0,0 to screen 1,1 fillcolor rgb "black" behind',
                xlabel => ['Date', textcolor => 'rgb "yellow"'],
                ylabel => ['Price', textcolor => 'rgb "yellow"'],
                title => ["$symbol Price & Volume", textcolor => "rgb 'white'"],
                key => ['on', 'outside', textcolor => 'rgb "yellow"'],
                border => 'linecolor rgbcolor "white"',
                xdata => 'time',
                xtics => {format => '%Y-%m-%d', rotate => -90, textcolor => 'orange', },
                ytics => {textcolor => 'orange'},
                bmargin => 0,
                lmargin => 9,
                rmargin => 2,
                %addon_gen,
                label => [1, $self->brand, textcolor => 'rgb "cyan"', at => "graph 0.90,0.03"],
            },
            {
                with => 'financebars',
                linecolor => 'white',
                legend => 'Price',
            },
            $data(,(0)), $data(,(1)), $data(,(2)), $data(,(3)), $data(,(4)),
            @general_plot,
        );
        if (@addon_plot) {
            $pwin->plot({
                    %binmode,
                    object => '1',
                    title => '',
                    key => ['on', 'outside', textcolor => 'rgb "yellow"'],
                    border => 'linecolor rgbcolor "white"',
                    ylabel => '',
                    xlabel => '',
                    xtics => '',
                    ytics => {textcolor => 'orange'},
                    bmargin => 0,
                    tmargin => 0,
                    lmargin => 9,
                    rmargin => 2,
                    size => ["1,0.2"], #bug in P:G:G
                    origin => [0, 0.2],
                    label => [1, "", at => "graph 0.90,0.03"],
                },
                @addon_plot,
            );
        }
        $pwin->plot({
                %binmode,
                title => '',
                key => ['on', 'outside', textcolor => 'rgb "yellow"'],
                border => 'linecolor rgbcolor "white"',
                ylabel => ['Volume (in 1M)', textcolor => 'rgb "yellow"'],
                xlabel => '',
                xtics => '',
                ytics => {textcolor => 'orange'},
                bmargin => 0,
                tmargin => 0,
                lmargin => 9,
                rmargin => 2,
                %addon_vol,
                label => [1, "", at => "graph 0.90,0.03"],
            },
            {
                with => 'impulses',
                legend => 'Volume',
                linecolor => 'cyan',
            },
            $data(,(0)), $data(,(5)) / 1e6,
            @volume_plot,
        );
    } elsif ($type eq 'CANDLE') {
        my %addon_gen = ();
        if (@addon_plot) {
            $addon_gen{size} = ["1, 0.7"];
            $addon_gen{origin} = [0, 0.3];
            $addon_gen{bmargin} = 0;
            $addon_gen{lmargin} = 9;
            $addon_gen{rmargin} = 2;
        }
        # use candlesticks feature of Gnuplot
        $pwin->plot({
                %binmode,
                object => '1 rectangle from screen 0,0 to screen 1,1 fillcolor rgb "black" behind',
                title => ["$symbol Open-High-Low-Close", textcolor => 'rgb "white"'],
                key => ['on', 'outside', textcolor => 'rgb "yellow"'],
                border => 'linecolor rgbcolor "white"',
                xlabel => ['Date', textcolor => 'rgb "yellow"'],
                ylabel => ['Price', textcolor => 'rgb "yellow"'],
                ytics => {textcolor => 'orange'},
                xdata => 'time',
                xtics => {format => '%Y-%m-%d', rotate => -90, textcolor => 'orange', },
                label => [1, $self->brand, textcolor => 'rgb "cyan"', at => "graph 0.90,0.03"],
                %addon_gen,
            },
            {
                with => 'candlesticks',
                linecolor => 'white',
                legend => 'Price',
            },
            $data(,(0)), $data(,(1)), $data(,(2)), $data(,(3)), $data(,(4)),
            @general_plot,
            @candle_plot,
        );
        if (@addon_plot) {
            $pwin->plot({
                    %binmode,
                    object => '1',
                    title => '',
                    key => ['on', 'outside', textcolor => 'rgb "yellow"'],
                    border => 'linecolor rgbcolor "white"',
                    ylabel => '',
                    xlabel => '',
                    xtics => '',
                    ytics => {textcolor => 'orange'},
                    bmargin => 0,
                    tmargin => 0,
                    lmargin => 9,
                    rmargin => 2,
                    size => ["1,0.3"], #bug in P:G:G
                    origin => [0, 0],
                    label => [1, "", at => "graph 0.90,0.03"],
                },
                @addon_plot,
            );
        }
    } elsif ($type eq 'CANDLEV') {
        my %addon_gen = ();
        my %addon_vol = ();
        if (@addon_plot) {
            $addon_gen{size} = ["1, 0.6"]; #bug in P:G:G
            $addon_gen{origin} = [0, 0.4];
            $addon_vol{size} = ["1, 0.2"]; #bug in P:G:G
            $addon_vol{origin} = [0, 0];
        } else {
            $addon_gen{size} = ["1, 0.7"]; #bug in P:G:G
            $addon_gen{origin} = [0, 0.3];
            $addon_vol{size} = ["1, 0.3"]; #bug in P:G:G
            $addon_vol{origin} = [0, 0];
            $addon_vol{object} = '1'; # needed as otherwise the addon plot does it
        }
        $pwin->plot({
                %binmode,
                object => '1 rectangle from screen 0,0 to screen 1,1 fillcolor rgb "black" behind',
                title => ["$symbol Price & Volume", textcolor => "rgb 'white'"],
                key => ['on', 'outside', textcolor => 'rgb "yellow"'],
                border => 'linecolor rgbcolor "white"',
                xlabel => ['Date', textcolor => 'rgb "yellow"'],
                ylabel => ['Price', textcolor => 'rgb "yellow"'],
                xdata => 'time',
                ytics => {textcolor => 'orange'},
                xtics => {format => '%Y-%m-%d', rotate => -90, textcolor => 'orange', },
                tmargin => '',
                bmargin => 0,
                lmargin => 9,
                rmargin => 2,
                %addon_gen,
                label => [1, $self->brand, textcolor => 'rgb "cyan"', at => "graph 0.90,0.03"],
            },
            {
                with => 'candlesticks',
                linecolor => 'white',
                legend => 'Price',
            },
            $data(,(0)), $data(,(1)), $data(,(2)), $data(,(3)), $data(,(4)),
            @general_plot,
            @candle_plot,
        );
        if (@addon_plot) {
            $pwin->plot({
                    %binmode,
                    object => '1',
                    title => '',
                    key => ['on', 'outside', textcolor => 'rgb "yellow"'],
                    border => 'linecolor rgbcolor "white"',
                    ylabel => '',
                    xlabel => '',
                    xtics => '',
                    ytics => {textcolor => 'orange'},
                    bmargin => 0,
                    tmargin => 0,
                    lmargin => 9,
                    rmargin => 2,
                    size => ["1,0.2"], #bug in P:G:G
                    origin => [0, 0.2],
                    label => [1, "", at => "graph 0.90,0.03"],
                },
                @addon_plot,
            );
        }
        $pwin->plot({
                %binmode,
                title => '',
                ylabel => ['Volume (in 1M)', textcolor => 'rgb "yellow"'],
                key => ['on', 'outside', textcolor => 'rgb "yellow"'],
                border => 'linecolor rgbcolor "white"',
                xtics => '',
                xlabel => '',
                ytics => {textcolor => 'orange'},
                bmargin => 0,
                tmargin => 0,
                lmargin => 9,
                rmargin => 2,
                %addon_vol,
                label => [1, "", at => "graph 0.90,0.03"],
            },
            {
                with => 'impulses',
                legend => 'Volume',
                linecolor => 'cyan',
            },
            $data(,(0)), $data(,(5)) / 1e6,
            @volume_plot,
        );
    } elsif ($type eq 'CLOSEV') {
        my %addon_gen = ();
        my %addon_vol = ();
        if (@addon_plot) {
            $addon_gen{size} = ["1, 0.6"]; #bug in P:G:G
            $addon_gen{origin} = [0, 0.4];
            $addon_vol{size} = ["1, 0.2"]; #bug in P:G:G
            $addon_vol{origin} = [0, 0];
        } else {
            $addon_gen{size} = ["1, 0.7"]; #bug in P:G:G
            $addon_gen{origin} = [0, 0.3];
            $addon_vol{size} = ["1, 0.3"]; #bug in P:G:G
            $addon_vol{origin} = [0, 0];
            $addon_vol{object} = '1'; # needed as otherwise the addon plot does it
        }
        $pwin->plot({
                %binmode,
                object => '1 rectangle from screen 0,0 to screen 1,1 fillcolor rgb "black" behind',
                title => ["$symbol Price & Volume", textcolor => "rgb 'white'"],
                key => ['on', 'outside', textcolor => 'rgb "yellow"'],
                border => 'linecolor rgbcolor "white"',
                ylabel => ['Close Price', textcolor => 'rgb "yellow"'],
                xlabel => ['Date', textcolor => 'rgb "yellow"'],
                xdata => 'time',
                xtics => {format => '%Y-%m-%d', rotate => -90, textcolor => 'orange', },
                ytics => {textcolor => 'orange'},
                bmargin => 0,
                lmargin => 9,
                rmargin => 2,
                %addon_gen,
                label => [1, $self->brand, textcolor => 'rgb "cyan"', at => "graph 0.90,0.03"],
            },
            {
                with => 'lines',
                linecolor => 'white',
                legend => 'Close Price',
            },
            $data(,(0)), $data(,(4)),
            @general_plot,
        );
        if (@addon_plot) {
            $pwin->plot({
                    %binmode,
                    object => '1',
                    title => '',
                    key => ['on', 'outside', textcolor => 'rgb "yellow"'],
                    border => 'linecolor rgbcolor "white"',
                    ylabel => '',
                    xlabel => '',
                    xtics => '',
                    ytics => {textcolor => 'orange'},
                    bmargin => 0,
                    tmargin => 0,
                    lmargin => 9,
                    rmargin => 2,
                    size => ["1,0.2"], #bug in P:G:G
                    origin => [0, 0.2],
                    label => [1, "", at => "graph 0.90,0.03"],
                },
                @addon_plot,
            );
        }
        $pwin->plot({
                %binmode,
                title => '',
                key => ['on', 'outside', textcolor => 'rgb "yellow"'],
                border => 'linecolor rgbcolor "white"',
                ylabel => ['Volume (in 1M)', textcolor => 'rgb "yellow"'],
                xlabel => '',
                xtics => '',
                ytics => {textcolor => 'orange'},
                bmargin => 0,
                tmargin => 0,
                lmargin => 9,
                rmargin => 2,
                %addon_vol,
                label => [1, "", at => "graph 0.90,0.03"],
            },
            {
                with => 'impulses',
                legend => 'Volume',
                linecolor => 'cyan',
            },
            $data(,(0)), $data(,(5)) / 1e6,
            @volume_plot,
        );
    } else {
        $type = 'CLOSE';
        my %addon_gen = ();
        if (@addon_plot) {
            $addon_gen{size} = ["1, 0.7"];
            $addon_gen{origin} = [0, 0.3];
            $addon_gen{bmargin} = 0;
            $addon_gen{lmargin} = 9;
            $addon_gen{rmargin} = 2;
        }
        $pwin->plot({
                %binmode,
                object => '1 rectangle from screen 0,0 to screen 1,1 fillcolor rgb "black" behind',
                title => ["$symbol Close Price", textcolor => 'rgb "white"'],
                key => ['on', 'outside', textcolor => 'rgb "yellow"'],
                border => 'linecolor rgbcolor "white"',
                xlabel => ['Date', textcolor => 'rgb "yellow"'],
                ylabel => ['Close Price', textcolor => 'rgb "yellow"'],
                xdata => 'time',
                xtics => {format => '%Y-%m-%d', rotate => -90, textcolor => 'orange', },
                ytics => {textcolor => 'orange'},
                label => [1, $self->brand, textcolor => 'rgb "cyan"', at => "graph 0.90,0.03"],
                %addon_gen,
            },
            {
                with => 'lines',
                linecolor => 'white',
                legend => 'Close Price',
            },
            $data(,(0)), $data(,(4)),
            @general_plot,
        );
        if (@addon_plot) {
            $pwin->plot({
                    %binmode,
                    object => '1',
                    title => '',
                    key => ['on', 'outside', textcolor => 'rgb "yellow"'],
                    border => 'linecolor rgbcolor "white"',
                    ylabel => '',
                    xlabel => '',
                    xtics => '',
                    ytics => {textcolor => 'orange'},
                    bmargin => 0,
                    tmargin => 0,
                    lmargin => 9,
                    rmargin => 2,
                    size => ["1,0.3"], #bug in P:G:G
                    origin => [0, 0],
                    label => [1, "", at => "graph 0.90,0.03"],
                },
                @addon_plot,
            );
        }
    }
    $pwin->end_multi;
    # make the current plot type the type
    $self->current->{plot_type} = $type if defined $type;
}

sub plot_data_highcharts {
    my ($self, $win, $data, $symbol, $type, $indicators, $buysell) = @_;
    return unless defined $data;
    $symbol = $self->current->{symbol} unless defined $symbol;
    $type = $self->current->{plot_type} unless defined $type;
    ### for OHLC type
    ## timestamp: data(,(0))
    ## OHLC: data(, (1)), data(, (2)), data(,(3)), data(,(4))
    ## Volume: data(, (5))
    $log->debug("Symbol $symbol. Plot type $type");
    ### we use Template toolkit to take a template, plug data in via variables
    ### and auto-generate an HTML page that will then render graphics as needed
    ### maybe all the data should be in the HTML form for easy generation
    ### and the JS code has to be fixed and pre-written.
    ### so the JS code uses variables that are defined in the HTML data that is printed by
    ### the template
    my $ttfile = get_file_path('chart.tt');
    $log->info("Template file path: $ttfile");
    my $html = File::Spec->catfile($self->tmpdir, lc "$symbol\_$type.html");
    ## highcharts requires timestamp in milliseconds
    ## transpose the data for JSON charting
    my $chart_type_pretty;
    my @charts = ();
    $type //= 'OHLC';
    my $next_y_axis = 0;
    my $has_volume_chart = 0;
    if ($type eq 'OHLC' or $type eq 'CANDLE') {
        $chart_type_pretty = ($type eq 'CANDLE') ? 'Candlestick' : 'OHLC Price';
        my $ppdl = encode_json pdl($data(,(0)) * 1000, $data(,(1)), $data(,(2)), $data(,(3)), $data(,(4)))->transpose->unpdl;
        $log->debug($ppdl);
        push @charts, {
            title => $symbol,
            data => $ppdl,
            type => ($type eq 'CANDLE') ? 'candlestick' : 'ohlc',
            id => lc "$symbol-$type",

lib/App/financeta/gui.pm  view on Meta::CPAN

                title => "Buy Signals",
                data => $bpdljs,
                type => 'line',
                id => lc "$symbol-buy-signals",
                y_axis => 0,
                is_signal => 1,
                marker_symbol => 'triangle',
                marker_color => 'green',
            };
            my $spdl = pdl($data(,(0)) * 1000, $sells)->transpose;
            my $sidx = $spdl((1))->which;#check if !0 is true
            my $spdlclean = $spdl->dice_axis(1, $sidx);
            $log->debug($spdlclean);
            my $spdljs = encode_json $spdlclean->unpdl;
            push @charts, {
                title => "Sell Signals",
                data => $spdljs,
                type => 'line',
                id => lc "$symbol-sell-signals",
                y_axis => 0,
                is_signal => 1,
                marker_symbol => 'triangle-down',
                marker_color => 'red',
            };
        } else {
            $log->warn("Unable to plot invalid buy-sell data");
        }
        if (ref $buysell->{rtpnl} eq 'PDL') {
            my $rpdl = pdl($data(, (0)) * 1000, $buysell->{rtpnl})->transpose;
            my $rpdljs = encode_json $rpdl->unpdl;
            push @charts, {
                title => "Runtime P&L",
                data => $rpdljs,
                type => 'area',
                id => lc "$symbol-runtime-pnl",
                y_axis => $next_y_axis + 1,
            };
        }
    }
    my %y_axes_index = ();
    foreach (@charts) {
        $y_axes_index{$_->{y_axis}}++;
    }
    my $cheight = 400;
    foreach (keys %y_axes_index) {
        $cheight += 200;
    }
    my $ttconf = {
        page => {
            title => "$chart_type_pretty plot of $symbol",
            close_on_idle => 1,
        },
        chart => {
            height => $cheight . "px",
            yaxes_index => [sort keys(%y_axes_index)],
            charts => \@charts,
            title => $symbol,
        },
    };
    my $tt = Template->new({ ABSOLUTE => 1 });
    my $ret = $tt->process($ttfile, $ttconf, $html, { binmode => ':utf8' });
    if ($ret) {
        my $url = "file://$html";
        my $ok = Browser::Open::open_browser($url, 1);
        if (not defined $ok) {
            message("Error finding a browser to open $url");
            $log->warn("Error finding a default browser to open $url");
        } elsif ($ok != 0) {
            message("Error opening $url");
            $log->warn("Error opening $url in default browser");
        }
    } else {
        $log->error("Failed to generate $html from $ttfile: " . $tt->error() . "\n");
        message("Failed to plot chart in a browser!");
    }
    # make the current plot type the type
    $self->current->{plot_type} = $type if defined $type;
}

1;

__END__
### COPYRIGHT: 2013-2025. Vikas N. Kumar. All Rights Reserved.
### AUTHOR: Vikas N Kumar <vikas@cpan.org>
### DATE: 3rd Jan 2014
### LICENSE: Refer LICENSE file

=head1 NAME

App::financeta::gui

=head1 SYNOPSIS

App::financeta::gui is a perl module allowing the user to perform technical
analysis on financial data stored as PDLs. It is the basis of the graphics
application L<App::financeta> which can be used by users to do financial stocks
research with Technical Analysis.

=head1 VERSION

0.16

=head1 METHODS

=over

=item B<new>

Creates a new instance of C<App::financeta::gui>. Takes in various properties that
the user might want to override. Check the B<PROPERTIES> section to view the
different properties.

=item B<run>

This function starts the graphical user interface (GUI) and uses
L<POE::Loop::Prima> and L<Prima> to do all its work. This is our current choice
of the GUI framework but it need not be in the future.

=back

=head1 PROPERTIES



( run in 1.437 second using v1.01-cache-2.11-cpan-5735350b133 )