#!/usr/bin/perl -w # #------------------------------------------------------------------------------ # Elevetrica Version 0.9 # Copyright 2004, 2008 Antony Jerome (antony.jerome at gmail dot com) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # To know more about the GNU General Public License visit http://www.gnu.org/licenses/ # # # Components of this program # 1. stocklist.csv - List of stocks. Sample version available at # - http://edotte.com/AJ/Elevetrica/stocklist.csv # 2. .csv - Actual data file for price/volume data # - is the stock identifier in stocklist.csv # 3. Elevetrica.pl - the main program (this file) # #------------------------------------------------------------------------------ use Tk 8.0; use Tk::HList; use Tk::widgets qw/Dialog/; use subs qw/build_menubar fini init stocklistsub/; use vars qw/$MW $VERSION/; use LWP::UserAgent; use Tk::DialogBox; use Tk::ProgressBar; use Tk::LabEntry; use Tk::Font; use Switch; use LWP::UserAgent; $VERSION = '0.9'; $GLOBAL_POINT_COUNT = 100; $GLOBAL_DEFAULT_CSTK = 0; # 1 => Plot CStk $GLOBAL_DEFAULT_EMA12 = 1; print "+------------------------------------------------------+\n"; print "| Elevetrica - Version ".$VERSION." |\n"; print "+------------------------------------------------------+\n"; #Fetch the current system time ($second, $minute, $hour, $_, $_, $_, $_, $_, $_) = localtime(); print "Current System Time $hour:$minute:$second\n"; # Main Window $MW = MainWindow->new(); $mMainWindowHeight = ($MW->screenheight)*0.8; $mMainWindowWidth = ($MW->screenwidth)*0.8; print "Screen settings detected as Height = $mMainWindowHeight\n"; print " Width = $mMainWindowWidth\n"; #left panel with list $list_frame = $MW -> Frame (-width => 0.2*0.0916*$mMainWindowWidth, -height => $mMainWindowHeight, -borderwidth => 5, -relief => 'groove')->pack(-side => "left", -fill => "both", -expand => 1); $top_frame = $list_frame -> Frame (-width => 0.2*0.0916*$mMainWindowWidth, -height => 0.0444*$mMainWindowHeight)->pack(-side => "top", -fill => "none", -expand => 0); $bot_frame = $list_frame -> Frame (-width => 0.2*0.0916*$mMainWindowWidth, -height => 0.9555*$mMainWindowHeight)->pack(-side => "bottom", -fill => "both", -expand => 1); $mMainWindowWidth = $mMainWindowWidth*1.0728; #right panel with plot $right_frame = $MW -> Frame (-width => 0.83*$mMainWindowWidth, -height => $mMainWindowHeight)->pack(-side => "right", -fill => "none", -expand => 1); #Frame for the canvas $plot_frame = $right_frame -> Frame (-width => 0.83*$mMainWindowWidth, -height => 0.96*$mMainWindowHeight)->pack(-side => "top", -fill => "none", -expand => 1); #Frame for the checkbuttons and radiobuttons $options_frame = $right_frame -> Frame (-width => 0.83*$mMainWindowWidth, -height => 0.0333*$mMainWindowHeight, -borderwidth => 5)->pack(-side => "bottom", -fill => "none", -expand => 1); #Frame for SMA Checkbuttons $options_sma_frame = $options_frame -> Frame (-width => 0.0833*$mMainWindowWidth, -height => 0.0333*$mMainWindowHeight, -borderwidth => 5)->pack(-side => "left", -fill => "none", -expand => 1); #Frame for EMA Checkbuttons $options_ema_frame = $options_frame -> Frame (-width => 0.0833*$mMainWindowWidth, -height => 0.0333*$mMainWindowHeight, -borderwidth => 5)->pack(-side => "left", -fill => "none", -expand => 1); #Frame for Radiobuttons $options_rb_frame = $options_frame -> Frame (-width => 0.0833*$mMainWindowWidth, -height => 0.0333*$mMainWindowHeight, -borderwidth => 5)->pack(-side => "left", -fill => "none", -expand => 1); #Frame for ChartType $options_chartType_frame = $options_frame -> Frame (-width => 0.0833*$mMainWindowWidth, -height => 0.0333*$mMainWindowHeight, -borderwidth => 5)->pack(-side => "left", -fill => "none", -expand => 1); #Frame for Points Radiobuttons $points_rb_frame = $options_frame -> Frame (-width => 0.0833*$mMainWindowWidth, -height => 0.0333*$mMainWindowHeight, -borderwidth => 5)->pack(-side => "left", -fill => "none", -expand => 1); # Font for the window $code_font = $MW->fontCreate('code', -family => 'verdana', -size => 10); #Update upto text input item $top_frame->LabEntry( -textvariable => \$end, -label => 'To', -width => 11, -labelPack => [-side => 'left'])->pack(-side => "left"); #Update button my $update_b = $top_frame->Button( -text => 'Go', -command => \&updatequote); $update_b->pack(-side => "right"); #Add new stock button my $newstock_b = $bot_frame->Button( -text => 'Add new Stock', -command => \&addnewstock); $newstock_b->pack(-side => "bottom"); #Dialog for "add new button" functionality $dialog = $MW->DialogBox( -title => "Add New Stock", -buttons => [ "Save Stock", "Cancel" ], ); #Label and Entry for "add new stock" $dialog->add("Label", -text => "Name")->pack(); $entry = $dialog->add("Entry", -width => 50)->pack(); #Dialog for "Adjust for split" functionality $splitadjust_dialog = $MW->DialogBox( -title => "Adjust for split", -buttons => [ "Adjust", "Cancel" ], ); #Label and Entry for "Adjust for split" $splitadjust_dialog->add("Label", -text => "Adjust upto (including this date)")->pack(); $splitadjust_upto = $splitadjust_dialog->add("Entry", -width => 30)->pack(); $splitadjust_dialog->add("Label", -text => "Divide by (for data before split)")->pack(); $splitadjust_factor = $splitadjust_dialog->add("Entry", -width => 20)->pack(); $splitadjust_dialog->add("Label", -text => "eg: Adjust upto 2-Dec-2004 (inclusive) and Divide by 2 (data before split)")->pack(-side => 'bottom'); #Dialog for "Adjust for split" functionality $sort_dialog = $MW->DialogBox( -title => "Warning - Confirm Sort and Exit", -buttons => [ "Sort and Exit", "Cancel" ], ); $sort_dialog->add("Label", -text => "Please confirm the Sort and Exit operation")->pack(); $sort_dialog->add("Label", -text => "WARNING: The program will terminate after sorting")->pack(); #Call the init procedure and stocksublist procedure init; stocklistsub; #Call the plot_frame_sub procedure which creates the canvas &plot_frame_sub; MainLoop; #----------------------------------------------------------------------- # This procedure plots the basic canvas #----------------------------------------------------------------------- sub plot_frame_sub { $CANV = $plot_frame->Canvas( -width => $mMainWindowWidth, -height => 0.9666*$mMainWindowHeight, -relief => 'sunken', -background => 'black', -borderwidth => 1 )->pack; #Bind ButtonPress for left button to call disp_coordinates $CANV->Tk::bind('' => \&disp_coordinate); $CANV->Tk::bind('' => sub{$CANV->delete('Vertline');}); #Default settings - may have to be changed depending on the screen size $XMIN = 0.0416*$mMainWindowWidth+25; $XMAX = 0.8083*$mMainWindowWidth+25; $Y10 = 0.0666*$mMainWindowHeight; $Y11 = 0.6666*$mMainWindowHeight; $Y20 = 0.7222*$mMainWindowHeight; $Y21 = 0.9444*$mMainWindowHeight; #Grid line in grey color $CANV->createGrid( 0, 0, 50, 50, -lines => 1, -dash => '.', -fill => 'grey33'); #X axis and Y axis for both price and volume $CANV->create('line', $XMIN, $Y10, $XMIN, $Y11, -fill => 'white', -width => 2 ); $CANV->create('line', $XMIN, $Y11, $XMAX, $Y11, -fill => 'white', -width => 2 ); $CANV->create('line', $XMIN, $Y20, $XMIN, $Y21, -fill => 'white', -width => 2 ); $CANV->create('line', $XMIN, $Y21, $XMAX, $Y21, -fill => 'white', -width => 2 ); #MA Plot button - relief and color are controlled dynamically #$relief = 'raised'; $sma20_cb = $options_sma_frame->Checkbutton(-text => "SMA20", -variable => \$sma20_value, -selectcolor => 'LightBlue', -command => sub { if ($sma20_value) { $ma_limit = 20; $plot_linecolor = 'blue'; $ma_plot_color = 'blue'; $sma20_cb ->configure(-selectcolor => 'blue',); &plot_ma; } else { $sma20_cb ->configure(-selectcolor => 'LightBlue'); $CANV->delete('CloseMAS_20'); } })->pack(-side => "top", -fill => "none", -expand => 0); $sma10_cb = $options_sma_frame->Checkbutton(-text => "SMA10", -variable => \$sma10_value, -selectcolor => 'LightBlue', -command => sub { if ($sma10_value) { $ma_limit = 10; $plot_linecolor = 'red'; $ma_plot_color = 'red'; $sma10_cb ->configure(-selectcolor => 'red'); &plot_ma; } else { $sma10_cb ->configure(-selectcolor => 'LightBlue'); $CANV->delete('CloseMAS_10'); } })->pack(-side => "top", -fill => "none", -expand => 0); $sma5_cb = $options_sma_frame->Checkbutton(-text => "SMA5 ", -variable => \$sma5_value, -selectcolor => 'LightBlue', -command => sub { if ($sma5_value) { $ma_limit = 5; $plot_linecolor = 'green'; $ma_plot_color = 'green'; $sma5_cb ->configure(-selectcolor => 'green'); &plot_ma; } else { $sma5_cb ->configure(-selectcolor => 'LightBlue'); $CANV->delete('CloseMAS_5'); } })->pack(-side => "top", -fill => "none", -expand => 0); $ema12_cb = $options_ema_frame->Checkbutton(-text => "EMA12", -variable => \$ema12_value, -selectcolor => 'LightBlue', -command => sub { if ($ema12_value) { $ma_limit = 12; $plot_linecolor = 'orange'; $ma_plot_color = 'orange'; $ema12_cb ->configure(-selectcolor => 'orange'); &plot_ema; } else { $ema12_cb ->configure(-selectcolor => 'LightBlue'); $CANV->delete("CloseMAExp12"); } })->pack(-side => "top", -fill => "none", -expand => 0); $ema6_cb = $options_ema_frame->Checkbutton(-text => "EMA6 ", -variable => \$ema6_value, -selectcolor => 'LightBlue', -command => sub { if ($ema6_value) { $ma_limit = 6; $plot_linecolor = 'magenta'; $ma_plot_color = 'magenta'; $ema6_cb ->configure(-selectcolor => 'magenta'); &plot_ema; } else { $ema6_cb ->configure(-selectcolor => 'LightBlue'); $CANV->delete("CloseMAExp6"); } })->pack(-side => "top", -fill => "none", -expand => 0); $macd_rb = $options_rb_frame->Radiobutton(-text => "MACD ", -value => 1, -variable => \$rb_value, -selectcolor => 'LightBlue', -command => \&radiochoose )->pack(-side => "top", -fill => "none", -expand => 0); $vol_rb = $options_rb_frame->Radiobutton(-text => "Volume", -value => 2, -variable => \$rb_value, -selectcolor => 'LightBlue', -command => \&radiochoose )->pack(-side => "top", -fill => "none", -expand => 0); #-------------------------------------------------------------------------- # Added for restricting number of points in the chart #-------------------------------------------------------------------------- $points50_rb = $points_rb_frame->Radiobutton(-text => "50 Points", -value => 50, -variable => \$points_rb_value, -selectcolor => 'LightBlue', -command => \&pointsRadioChoose )->pack(-side => "top", -fill => "none", -expand => 0); $points100_rb = $points_rb_frame->Radiobutton(-text => "100 Points", -value => 100, -variable => \$points_rb_value, -selectcolor => 'LightBlue', -command => \&pointsRadioChoose )->pack(-side => "top", -fill => "none", -expand => 0); $points200_rb = $points_rb_frame->Radiobutton(-text => "200 Points", -value => 200, -variable => \$points_rb_value, -selectcolor => 'LightBlue', -command => \&pointsRadioChoose )->pack(-side => "top", -fill => "none", -expand => 0); $pointsAll_rb = $points_rb_frame->Radiobutton(-text => "All Points", -value => 300000, -variable => \$points_rb_value, -selectcolor => 'LightBlue', -command => \&pointsRadioChoose )->pack(-side => "top", -fill => "none", -expand => 0); #-------------------------------------------------------------------------- # Added for candlestick charting #-------------------------------------------------------------------------- $cdlstk_cb = $options_chartType_frame->Checkbutton(-text => "Cstk ", -variable => \$chartType_value, -selectcolor => 'LightBlue', -command => \&switchChartType )->pack(-side => "top", -fill => "none", -expand => 0); } #------------------------------------------------------------------ # Points chooser - Radio Button Actions #------------------------------------------------------------------ sub pointsRadioChoose { $points50_rb ->configure(-selectcolor => 'LightBlue'); $points100_rb ->configure(-selectcolor => 'LightBlue'); $points200_rb ->configure(-selectcolor => 'LightBlue'); $pointsAll_rb ->configure(-selectcolor => 'LightBlue'); if ($points_rb_value == 50) { $GLOBAL_POINT_COUNT = 50; $points50_rb ->configure(-selectcolor => 'blue'); } elsif ($points_rb_value == 100) { $GLOBAL_POINT_COUNT = 100; $points100_rb ->configure(-selectcolor => 'blue'); } elsif ($points_rb_value == 200) { $GLOBAL_POINT_COUNT = 200; $points200_rb ->configure(-selectcolor => 'blue'); } elsif ($points_rb_value == 300000) { $GLOBAL_POINT_COUNT = 300000; $pointsAll_rb ->configure(-selectcolor => 'blue'); } &restorePlotState; } #------------------------------------------------------------------------------ # This function restores the plot to the state that existed before zoom in/out #------------------------------------------------------------------------------ sub restorePlotState { my $rb_value_tmp = $rb_value; my $chartType_value_tmp = $chartType_value; my $sma20_value_tmp = $sma20_value; my $sma10_value_tmp = $sma10_value; my $sma5_value_tmp = $sma5_value; my $ema12_value_tmp = $ema12_value; my $ema6_value_tmp = $ema6_value; &xswitchplot; $rb_value = $rb_value_tmp; $chartType_value = $chartType_value_tmp ; $sma20_value = $sma20_value_tmp; $sma10_value = $sma10_value_tmp; $sma5_value = $sma5_value_tmp; $ema12_value = $ema12_value_tmp; $ema6_value = $ema6_value_tmp; # Plot MACD/Volume according to previous view &radiochoose; # Plot Candlestick if that was being plotted in previous view &switchChartType; if ($sma20_value) { $ma_limit = 20; $plot_linecolor = 'blue'; $ma_plot_color = 'blue'; $sma20_cb ->configure(-selectcolor => 'blue',); &plot_ma; } if ($sma10_value) { $ma_limit = 10; $plot_linecolor = 'red'; $ma_plot_color = 'red'; $sma10_cb ->configure(-selectcolor => 'red'); &plot_ma; } if ($sma5_value) { $ma_limit = 5; $plot_linecolor = 'green'; $ma_plot_color = 'green'; $sma5_cb ->configure(-selectcolor => 'green'); &plot_ma; } if ($ema12_value) { $ma_limit = 12; $plot_linecolor = 'orange'; $ma_plot_color = 'orange'; $ema12_cb ->configure(-selectcolor => 'orange'); &plot_ema; } if ($ema6_value) { $ma_limit = 6; $plot_linecolor = 'magenta'; $ma_plot_color = 'magenta'; $ema6_cb ->configure(-selectcolor => 'magenta'); &plot_ema; } } #------------------------------------------------------------------ # MACD/Volume - Radio Button Actions #------------------------------------------------------------------ sub radiochoose { if ($rb_value == 1) { $CANV->delete('AuxVolume'); $ma_limit = 12; $plot_linecolor = '#2020FF'; $ma_plot_color = 'blue'; $macd_rb ->configure(-selectcolor => 'blue'); $vol_rb ->configure(-selectcolor => 'LightBlue'); &plot_macd; } elsif ($rb_value == 2) { $vol_rb ->configure(-selectcolor => 'red'); $macd_rb ->configure(-selectcolor => 'LightBlue'); $CANV->delete("AuxMACD"); &plot_volume; } } #------------------------------------------------------------------ # CandleStick - CheckBox Action #------------------------------------------------------------------ sub switchChartType { if ($chartType_value) { $cdlstk_cb ->configure(-selectcolor => 'red'); &plot_cstk; } else { $cdlstk_cb ->configure(-selectcolor => 'LightBlue'); $CANV->delete("candle"); } } #------------------------------------------------------------------ # Print Canvas coordinates #------------------------------------------------------------------ sub disp_coordinate { #Get the canvas object my($canvas) = @_; #Get the XEvent corresponding to the canvas object my $e = $canvas->XEvent; #Extract info from the XEvent my($canv_x, $canv_y) = ($e->x, $e->y); #Display coordinates only if the pointer is within the graph range if ( ($plotxspace ne undef) && ($canv_x > $XMIN+9) && ($canv_x < $XMAX-7)&& ( ( ($canv_y >($Y10))&&($canv_y<($Y11)) )|| ( ($canv_y >($Y20))&&($canv_y<($Y21)) ) ) ) { $CANV->create('line', $canv_x-2, $canv_y, $canv_x+2, $canv_y, -fill => 'red', -width => 5, -tags => ['plot', 'Vertline'] ); $CANV->create('line', $canv_x, $canv_y-2, $canv_x, $canv_y+2, -fill => 'red', -width => 5, -tags => ['plot', 'Vertline'] ); $CANV->create('line', 0, $canv_y, 900, $canv_y, -fill => '#8cc96e', -width => 2, -tags => ['plot', 'Vertline'] ); #Reverse mapping the canvas point to line number in data.csv $num = 1+ (($canv_x - $XMIN - 10)/$plotxspace);print "\n\nNUM=>".$num."\n"; #Rounding is done to ensure integer values $num = (int($num + .5 ));print "NUM=>".$num."\n";print "NUMDIFF=>".$#list-$num."\n"."DATE=>".$plotdate[$num-1]."\n"; #Retieve data from the file currently loaded into @list my @details = split(/,/,$list[$#list-$num]); chomp($details[$#details]); #Remove text written already for displaying previous coordinates $CANV->delete('text'); #Create new text for diplaying current coordinates $CANV->createText(($XMIN+$XMAX)/2, $Y21+10, -fill => 'white', -text => "Date = ".$plotdate[$num-1]." ,Open = $details[1], High = $details[2], Low = $details[3], Close = ".$details[4]." , Volume = ".$details[5] , -font => $valuefont, -tags => ['text']); } } # end display_coordinates #------------------------------------------------------------------ # Main procedure which invokes the Price/Vol plotters # This is invoked when the scrip is switched in the left pane #------------------------------------------------------------------ sub plot_sub { $plot_linecolor = 'white'; #Open data file for scrip to be plotted open (STOCKDATA, "<$plotscrip.csv") || die ("Error: Could not open file - $!"); @listall=; @list = getDataLines(@listall); close (STOCKDATA); #Default font my $titlefont = $CANV->Font('family' => "verdana", point => 140 ); #delete all previous plots $CANV->delete('plot'); $CANV->delete('text'); #Write down titles - information for price and volume plots $CANV->createText(($XMIN+$XMAX)/2, 30, -fill => 'white', -text => "Chart for $plotscrip", -font => $titlefont, -tags => ['plot']); #plotval will be the array taken in by the plotter procedure @plotval = (); @plotdate = (); @openPlotVal = (); @highPlotVal = (); @lowPlotVal = (); my @temp = (); #Populating @plotval for($i=1; $i<$#list;$i++) { @temp = split(/,/, $list[$i]); push @plotval, $temp[4]; push @plotdate, $temp[0]; push @openPlotVal, $temp[1]; push @highPlotVal, $temp[2]; push @lowPlotVal, $temp[3]; } #Reverse the array since data is in reverse order( since latest data is found at the beginning of the data file) @plotval = reverse(@plotval); @plotdate = reverse(@plotdate); @openPlotVal = reverse(@openPlotVal); @highPlotVal = reverse(@highPlotVal); @lowPlotVal = reverse(@lowPlotVal); #Keep the values in a reserve array @plot_reserve = @plotval; #Find the min and max values so that the y limits may be determined $maxplotval = Max(\@plotval); $global_top_maxplotval = $maxplotval; $minplotval = Min(\@plotval); $global_top_minplotval = $minplotval; #With the plotcontext value the plotter decides where the plot is to go. ie. price or volume $plotcontext = "Close"; &plot; #&plot_volume; # By default, plot MACD - not volume $ma_limit = 12; $plot_linecolor = '#2020FF'; $ma_plot_color = 'blue'; $macd_rb ->configure(-selectcolor => 'blue'); $vol_rb ->configure(-selectcolor => 'LightBlue'); &plot_macd; # 100 Points RB is selected by default if ($GLOBAL_POINT_COUNT == 100) { $points100_rb ->configure(-selectcolor => 'blue'); } elsif ($GLOBAL_POINT_COUNT == 50) { $points50_rb ->configure(-selectcolor => 'blue'); } elsif ($GLOBAL_POINT_COUNT == 200) { $points200_rb ->configure(-selectcolor => 'blue'); } elsif ($GLOBAL_POINT_COUNT == 300000) { $pointsAll_rb ->configure(-selectcolor => 'blue'); } if ($GLOBAL_DEFAULT_CSTK == 1) { $chartType_value = 1; $cdlstk_cb ->configure(-selectcolor => 'red'); &plot_cstk; } if ($GLOBAL_DEFAULT_EMA12 == 1) { $ema12_value = 1; $ma_limit = 12; $plot_linecolor = 'orange'; $ma_plot_color = 'orange'; $ema12_cb ->configure(-selectcolor => 'orange'); &plot_ema; } } #------------------------------------------------------------------ # Volume plotter #------------------------------------------------------------------ sub plot_volume { $CANV->delete('AuxMACD'); $plot_linecolor = 'white'; #Default font my $titlefont = $CANV->Font('family' => "verdana", point => 140 ); $CANV->createText(500, 630, -fill => 'white', -text => "Volume", -font => $titlefont, -tags => ['plot', 'AuxVolume']); #Open data file for scrip to be plotted open (STOCKDATA, "<$plotscrip.csv") || die ("Could not open file. $!"); @listall=; @list = getDataLines(@listall); close (STOCKDATA); #Plot the volume @plotval = (); @plotdate = (); @temp = (); #Populating @plotval for($i=1; $i<$#list;$i++) { @temp = split(/,/, $list[$i]); push @plotval, $temp[5]; push @plotdate, $temp[0]; } #Reverse the array since data is in reverse order( since latest data is found at the beginning of the data file) @plotval = reverse(@plotval); @plotdate = reverse(@plotdate); $maxplotval = Max(\@plotval); $minplotval = Min(\@plotval); #With the plotcontext value the plotter decides where the plot is to go. ie. price or volume $plotcontext = "AuxVolume"; &plot; } #------------------------------------------------------------------ # MA plotter #------------------------------------------------------------------ sub plot_ma { #Define the default font $valuefont = $CANV->Font('family' => "verdana", point => 95, weight => 'bold' ); #Another font my $titlefont = $CANV->Font('family' => "verdana", point => 140 ); #Transfer the values from the reserve array @plotval = @plot_reserve; #Calculations for the moving average my @tempval =(); for($i = 0; $i<=$#plotval-$ma_limit+1; $i++) { my $price_sum = 0; for($j = 0;$j<$ma_limit;$j++) { $price_sum = $price_sum + $plotval[$j+$i]; } my $avg = $price_sum/$ma_limit; push @tempval, $avg; } #Transfer the calculation results to @plotval for plotting @plotval = @tempval; #Find the min and max values so that the y limits may be determined $maxplotval = $global_top_maxplotval; $minplotval = $global_top_minplotval; #Plotcontext is set as CloseMA since the plot needs to be x-shifted by the MA period $plotcontext = "CloseMAS_".$ma_limit; &plot; } #------------------------------------------------------------------ # EMA plotter #------------------------------------------------------------------ sub plot_ema { my $ema_percentage = 2/($ma_limit+1); my $ema_subtracted = (1-$ema_percentage); @plotval = (); @temp = (); @tempval =(); for($i = 0; $i<=$#plot_reserve-$ma_limit+1; $i++) { my $price_sum = 0; if ($i == 0) { for($j = 0;$j<$ma_limit;$j++) { $price_sum = $price_sum + $plot_reserve[$j+$i]; } $avg = $price_sum/$ma_limit; push @tempval, $avg; } else { my $lastclose = $plot_reserve[$i+$ma_limit-1]; $avg = $ema_percentage*$lastclose + $ema_subtracted*$avg; push @tempval, $avg; } } @plotval = @tempval; if ($plotcontext ne "AuxMACD") { #Find the min and max values so that the y limits may be determined $maxplotval = $global_top_maxplotval; $minplotval = $global_top_minplotval; $plotcontext = "CloseMAExp".$ma_limit; &plot; } } #------------------------------------------------------------------ # MACD plotter #------------------------------------------------------------------ sub plot_macd { $plotcontext = "AuxMACD"; $ma_limit = 6; &plot_ema; @ema6 = @plotval; $ma_limit = 12; &plot_ema; @ema12 = @plotval; @macd = (); for ($i = 0; $i<=$#ema12; $i++) { $temp = $ema6[$i+6]-$ema12[$i]; push @macd, $temp; } @plotval = @macd; $ma_limit = 12; #Find the min and max values so that the y limits may be determined $maxplotval = Max(\@plotval); $minplotval = Min(\@plotval); $CANV->delete('AuxVolume'); $plotcontext = "AuxMACD"; &plot; #Plot the signal - ema of ema differences #Safe store for plot_reserve @safe_reserve = @plot_reserve; @plot_reserve = @plotval; $plot_linecolor = '#FF1717'; $ma_plot_color = 'red'; $ma_limit = 4; &plot_ema; #ma limit is set as 16 since this is an ema of ema differences $ma_limit = 16; $plotcontext = "AuxMACD"; &plot; @plot_reserve = @safe_reserve; my $titlefont = $CANV->Font('family' => "verdana", point => 140 ); $CANV->createText(330, 630, -fill => 'White', -text => "MACD Legend => ", -font => $titlefont, -tags => ['plot', 'AuxMACD']); $CANV->createText(450, 630, -fill => 'Blue', -text => "--- MACD", -font => $titlefont, -tags => ['plot', 'AuxMACD']); $CANV->createText(540, 630, -fill => 'white', -text => "--- Centreline", -font => $titlefont, -tags => ['plot', 'AuxMACD']); $CANV->createText(650, 630, -fill => 'red', -text => "--- Signal line", -font => $titlefont, -tags => ['plot', 'AuxMACD']); $plotcontext = " "; } #------------------------------------------------------------------ # Scrip switcher #------------------------------------------------------------------ sub xswitchplot { $sma5_value = 0; $sma10_value = 0; $sma20_value = 0; $ema12_value = 0; $ema6_value = 0; $rb_value = 1; $chartType_value = 0; $ema6_cb ->configure(-selectcolor => 'LightBlue'); $ema12_cb ->configure(-selectcolor => 'LightBlue'); $sma20_cb ->configure(-selectcolor => 'LightBlue'); $sma10_cb ->configure(-selectcolor => 'LightBlue'); $sma5_cb ->configure(-selectcolor => 'LightBlue'); $macd_rb ->configure(-selectcolor => 'LightBlue'); $vol_rb ->configure(-selectcolor => 'LightBlue'); $cdlstk_cb ->configure(-selectcolor => 'LightBlue'); #Open the file corresponding to the stock being selected open (STOCKLIST, "; close (STOCKLIST); #Get selection info from the HList @hlistselection = $hlist->info("selection"); my @temp = split (/,/, $list[$hlistselection[0]]); $plotscrip = $temp[0]; &plot_sub; $splitadjust_menu ->configure(-label => "Adjust $plotscrip for Splits"); #Debug Message print "Viewing chart No: $hlistselection[0] \n"; } #------------------------------------------------------------------ # Main plotter #------------------------------------------------------------------ sub plot { #plots content in @plotval - plotcontext determines where the plot is done #Default font $valuefont = $CANV->Font('family' => "verdana", point => 95, weight => 'bold' ); #Number of points to be plotted $numpoints = $#plotval; #The offset and color are required for the MA Plot - default values are provided initially $ma_plotx_offset = 0; #Check the plotcontext to determine where the plot is to be done if ($plotcontext =~ m/^Close$/) { #Ratio for mapping the stock prices onto the space alloted in the canvas $plotratio = ($Y10-$Y11+60)/($maxplotval - $minplotval); #Yshift is the amount by which the plot needs to be pushed up- depends on plotcontext $yshift = $Y11-30; #Provide y-axis values min, max and mid $CANV->createText($XMIN-22, $Y10+30, -fill => 'white', -text => $maxplotval, -font => $valuefont, -tags => ['plot']); $CANV->createText($XMIN-22, ($Y11+$Y10)/2, -fill => 'white', -text => (sprintf("%.2f", ($maxplotval+$minplotval)/2)), -font => $valuefont, -tags => ['plot']); $CANV->createText($XMIN-22, $Y11-30, -fill => 'white', -text => $minplotval, -font => $valuefont, -tags => ['plot']); #Provide x-axis values min and max $CANV->createText($XMIN, $Y11+10, -fill => 'white', -text => $plotdate[0], -font => $valuefont, -tags => ['plot']); $CANV->createText($XMAX, $Y11+10, -fill => 'white', -text => $plotdate[$#plotdate], -font => $valuefont, -tags => ['plot']); } elsif ($plotcontext =~ m/^Aux/) { #Volume plot my $tempDenominator = ($maxplotval - $minplotval); if($tempDenominator != 0) { #Ratio for mapping the stock prices onto the space alloted in the canvas $plotratio = ($Y20-$Y21+30)/$tempDenominator; #Yshift is the amount by which the plot needs to be pushed up- depends on plotcontext $yshift = $Y21-15; if ($plotcontext =~ m/^AuxVolume$/) { #Provide y-axis values min, max and mid $CANV->createText($XMIN-22, $Y20+30, -fill => 'white', -text => (sprintf("%.0f",$maxplotval/1000))."K", -font => $valuefont, -tags => ['plot',$plotcontext]); $CANV->createText($XMIN-22, ($Y21+$Y20)/2, -fill => 'white', -text => (sprintf("%.0f", ($maxplotval+$minplotval)/2000))."K", -font => $valuefont, -tags => ['plot',$plotcontext]); $CANV->createText($XMIN-22, $Y21-30, -fill => 'white', -text => (sprintf("%.0f",$minplotval/1000))."K", -font => $valuefont, -tags => ['plot',$plotcontext]); #NOTE: X-axis values are not repeated since they are already provided in price plot } } } if ($plotcontext =~ m/^AuxMACD$/) { #This is done since the @plotval contains less elements than a price plot - so compensate for that loss $numpoints = $#plotval + $ma_limit - 2; #Adjust plotxspace - else the values would get stretched in time and x-shift would'nt happen $plotxspace = ($XMAX - $XMIN -20)/($numpoints); #2 - since 1 to 9 can include 10 points $ma_plotx_offset = $plotxspace*($ma_limit-2); @tempval = @plotval; @plotval = (); foreach (@tempval) { push @plotval, "0"; } #Provide y-axis values min, max and mid $CANV->createText($XMIN-22, $Y20+30, -fill => 'white', -text => (sprintf("%.2f", $maxplotval)), -font => $valuefont, -tags => ['plot', $plotcontext]); $CANV->createText($XMIN-22, ($Y21+$Y20)/2, -fill => 'white', -text => (sprintf("%.2f", ($maxplotval+$minplotval)/2)), -font => $valuefont, -tags => ['plot', $plotcontext]); $CANV->createText($XMIN-22, $Y21-30, -fill => 'white', -text => (sprintf("%.2f", $minplotval)), -font => $valuefont, -tags => ['plot', $plotcontext]); for($i=0;$i< $#plotval;$i++) { #Y-values $ploty1 = (($plotval[$i]-$minplotval)*$plotratio + $yshift ); $ploty2 = (($plotval[$i+1]-$minplotval)*$plotratio + $yshift ); #X-values $plotx1 = $ma_plotx_offset + $XMIN +10 + ($plotxspace * ($i)); $plotx2 = $ma_plotx_offset + $XMIN +10 + ($plotxspace * ($i+1)); #join the points by lines with the required color $CANV->create('line', $plotx1, $ploty1, $plotx2, $ploty2, -fill => 'white', -tags => ['plot', $plotcontext]); } @plotval = @tempval; } #For the MA plot if ($plotcontext =~ m/^CloseMA/) { #Ratio for mapping the stock prices onto the space alloted in the canvas $plotratio = ($Y10-$Y11+60)/($maxplotval - $minplotval); #Yshift is the amount by which the plot needs to be pushed up- depends on plotcontext $yshift = $Y11-30; #This is done since the @plotval contains less elements than a price plot - so compensate for that loss $numpoints = $#plotval + $ma_limit - 2 ; #Adjust plotxspace - else the values would get stretched in time and x-shift would'nt happen $plotxspace = ($XMAX - $XMIN -20)/($numpoints); #2 - since 1 to 9 can include 10 points $ma_plotx_offset = $plotxspace*($ma_limit-2); } else { #Values of plotxspace in cases other than MA $plotxspace = ($XMAX - $XMIN -20)/($numpoints); #2 - since 1 to 9 can include 10 points } #Actual plotting happens here for($i=0;$i< $#plotval;$i++) { #Y-values $ploty1 = (($plotval[$i]-$minplotval)*$plotratio + $yshift ); $ploty2 = (($plotval[$i+1]-$minplotval)*$plotratio + $yshift ); #X-values $plotx1 = $ma_plotx_offset + $XMIN +10 + ($plotxspace * ($i)); $plotx2 = $ma_plotx_offset + $XMIN +10 + ($plotxspace * ($i+1)); #join the points by lines with the required color $CANV->create('line', $plotx1, $ploty1, $plotx2, $ploty2, -fill => $plot_linecolor, -tags => ['plot', $plotcontext]); } } #------------------------------------------------------------------ # Plots the candlestick #------------------------------------------------------------------ sub plot_cstk { #Number of points to be plotted $numpoints = $#plot_reserve; # Logically should have used max(high) and min(low) # Not using them since the line + CDL overlap will not match if the plotratios are diff for Line/CDL my $cstk_maxPlotVal = Max(\@plot_reserve); my $cstk_minPlotVal = Min(\@plot_reserve); my $candle_plot_color = 'green'; #Ratio for mapping the stock prices onto the space alloted in the canvas $plotratio = ($Y10-$Y11+60)/($cstk_maxPlotVal - $cstk_minPlotVal); #Yshift is the amount by which the plot needs to be pushed up- depends on plotcontext $yshift = $Y11-30; #Values of plotxspace in cases other than MA $plotxspace = ($XMAX - $XMIN -20)/($numpoints); #2 - since 1 to 9 can include 10 points #Actual plotting happens here for($i=0;$i<= $#plot_reserve;$i++) { #Y-value $open_plot_y = (($openPlotVal[$i]-$cstk_minPlotVal)*$plotratio + $yshift ); $high_plot_y = (($highPlotVal[$i]-$cstk_minPlotVal)*$plotratio + $yshift ); $low_plot_y = (($lowPlotVal[$i]-$cstk_minPlotVal)*$plotratio + $yshift ); $close_plot_y = (($plot_reserve[$i]-$cstk_minPlotVal)*$plotratio + $yshift ); #X-value $plot_x = $XMIN +10 + ($plotxspace * ($i)); #determine the color of the candle #NOTE: The condition needs to be reversed since here Y coordinates start from top #White Candle => white #Black Candle => red if($close_plot_y < $open_plot_y ) { $candle_plot_color = 'green'; } else { $candle_plot_color = 'red'; } $CANV->create('line', $plot_x, $high_plot_y, $plot_x, $low_plot_y, -fill => $candle_plot_color, -tags => ['candle', 'plot']); $CANV->createRectangle( $plot_x - 2, $open_plot_y, $plot_x + 2, $close_plot_y, -fill => $candle_plot_color, -outline => $candle_plot_color, -tags => ['candle', 'plot']); } } #------------------------------------------------------------------ # Builds the menubar #------------------------------------------------------------------ sub build_menubar { #Creating the Menu my $menubar = $MW->Menu; $MW->configure(-menu => $menubar); #The following are the menus my $file = $menubar->cascade(-label => '~File', -tearoff => 0); my $help = $menubar->cascade(-label => '~Help', -tearoff => 0); #The following are the sub-menus in 'File' $file->command(-label => "Update All", -command => \&updatequote); $file->separator; $splitadjust_menu = $file->command(-label => "Adjust for Splits", -command => \&splitadjust); $file->separator; $file->command(-label => "Sort Quotes and Exit", -command => \"esorter); $file->separator; $file->command(-label => "Quit", -command => \&fini); #The following are the sub-menus in 'Help' $help->command(-label => 'Quote Information'); $help->separator; $help->command(-label => 'Version'); #Dialog to be associated with 'Version' my $ver_dialog = $MW->Dialog(-title => 'Elevetrica 0.9', -text => " Elevetrica $VERSION\n Updated: 3rd Feb 2008\nCopyright 2008, Antony Jerome\n Elevetrica Inc.", -buttons => ['OK'], -bitmap => 'info', -font => $code_font); #Dialog to be associated with 'About' $about_dialog = $MW->Dialog(-title => 'Info', -buttons => ['OK'], -font => $code_font); $upd_compl_dialog = $MW->DialogBox( -title => "Updated", -buttons => [ "OK" ], ); my $menu = $help->cget('-menu'); $menu->entryconfigure('Version', -command => [$ver_dialog => 'Show']); $menu->entryconfigure('Quote Information', -command => [$about_dialog => 'Show']); $menubar; # return the menubar } # end build_menubar #------------------------------------------------------------------ # Cleanup method #------------------------------------------------------------------ sub fini { print "-------------- Exiting Elevetrica $VERSION ---------------\n"; print "-----------------------------------------------------------\n"; exit; } #end fini #------------------------------------------------------------------ # Initialization method #------------------------------------------------------------------ sub init { $MW->title("Elevetrica $VERSION"); my $menubar = build_menubar; } #end init #------------------------------------------------------------------ # Adds a new scrip to the plotter #------------------------------------------------------------------ sub addnewstock { my $button; my $done = 0; do { # show the dialog $button = $dialog->Show; # act based on what button has been pressed if ($button eq "Save Stock") { my $name = $entry->get; if (defined($name) && length($name)) { print "Adding Scrip - $name\n"; #Create new file my $data = $name.".csv"; open (STOCKDATA, "+>>$data") || die ("Error: Could not open file - $!"); close (STOCKDATA); #write new stock info into stocklist file open (STOCKLIST, "; close (STOCKLIST); $found = 0; #Add to stocklist open (STOCKLIST, ">stocklist.csv") || die ("Error: Could not open file - $!"); for(my $i=0;$i<$#list;$i++) { my @listdata = split(/,/, $list[$i]); if ($listdata[0] eq $name) { $found = 1; } print STOCKLIST $list[$i]; } if ($found == 0) { print STOCKLIST $name.",NA\n"; } #End remark for stocklist print STOCKLIST "\n"; close (STOCKLIST); my $count = $#list + 1; $about_dialog->configure(-text=> "Elevetrica currently monitors $count stocks "); #Add rows $hlist->add($#list); $hlist->itemCreate($#list, 0, -text => $name); $hlist->itemCreate($#list, 1, -text => "NA"); $hlist->update(); $done = 1; } else { print "Please give a valid stock code\n"; } } else { $done = 1; } } until $done; } #------------------------------------------------------------------ # Adjusts a scrip for splits #------------------------------------------------------------------ sub splitadjust { #Open the file corresponding to the stock being selected open (STOCKLIST, "; close (STOCKLIST); #Get selection info from the HList @hlistselection = $hlist->info("selection"); my @temp = split (/,/, $list[$hlistselection[0]]); my $data = $temp[0].".csv"; open (STOCKDATA, "<$data") || die ("Error: Could not open file - $!"); @init=; close (STOCKDATA); my $button; my $done = 0; do { # show the dialog $button = $splitadjust_dialog->Show; # act based on what button has been pressed if ($button eq "Adjust") { $upto = $splitadjust_upto->get; $factor = $splitadjust_factor->get; if (defined($upto) && length($upto) && defined($factor) && length($factor)) { $adjust_status = 0; for ($i = 1 ; $i<$#init; $i++) { my @tempstorage = split(/,/, $init[$i]); if ($tempstorage[0] eq $upto) { for($k = $i; $k<$#init; $k++) { @stagetwo = (); @stagetwo = split(/,/, $init[$k]); $stagetwo[1] = sprintf("%.2f",($stagetwo[1]/$factor)); $stagetwo[2] = sprintf("%.2f",($stagetwo[2]/$factor)); $stagetwo[3] = sprintf("%.2f",($stagetwo[3]/$factor)); $stagetwo[4] = sprintf("%.2f",($stagetwo[4]/$factor)); $stagetwo[6] = sprintf("%.2f",($stagetwo[6]/$factor)); $stagetwo[5] = sprintf("%.2f",($stagetwo[5]*$factor)); $init[$k] = $stagetwo[0].",". $stagetwo[1].",". $stagetwo[2].",". $stagetwo[3].",". $stagetwo[4].",". $stagetwo[5].",". $stagetwo[6]."\n"; } $adjust_status = 1; } if ($adjust_status == 1) { last; } } open (STOCKDATA, ">$data") || die ("Could not open file. $!"); print STOCKDATA @init; close (STOCKDATA); $done = 1; &xswitchplot; } else { print "Please enter a valid date and split factor\n"; } } else { $done = 1; } } until $done; } #------------------------------------------------------------------ # Prepares the Stocklist in left pane #------------------------------------------------------------------ sub stocklistsub { #Define the HList $hlist = $bot_frame->Scrolled("HList", -header => 1, -columns => 2, -scrollbars => 'osoe', -selectbackground => 'SeaGreen3', )->pack(-expand => 1, -fill => 'y'); foreach (qw/1 Down Up/) { $hlist->bind("<$_>" => \&xswitchplot); } #Define HList headers $hlist->header('create', 0, -text => 'Stock'); $hlist->header('create', 1, -text => 'LastUpd'); #Open the Stocklist file to obtain data for the HList open (STOCKLIST, "; for(my $i=0;$i<$#list;$i++) { $about_dialog->configure(-text=> "Elevetrica currently monitors $#list stocks "); #Split the csv values in stocklist.csv my @alldata = split(/,/, $list[$i]); #Add rows $hlist->add($i); #Remove the newline character chomp($alldata[1]); $hlist->itemCreate($i, 0, -text => $alldata[0]); $hlist->itemCreate($i, 1, -text => $alldata[1]); } close (STOCKLIST); # Progress Bar to indicate stock update progress. $progress = $list_frame->ProgressBar( -width => 20, -length => 150, -gap => 0, -troughcolor => 'LightSkyBlue3', -relief => 'groove', -anchor => 'w', -from => 0, -to => 100, -blocks => 10, -colors => [0, 'green', 50, 'yellow' , 80, 'red'], -variable => \$percent_done )->pack(); $progress->value(0); } #------------------------------------------------------------------ # Sort scrips in the left pane #------------------------------------------------------------------ sub quotesorter { do { # show the dialog my $button = $sort_dialog->Show; # act based on what button has been pressed if ($button eq "Sort and Exit") { my %temphash =(); open (STOCKLIST, "; close (STOCKLIST); for($i=0; $i<$#list; $i++) { @data = split(/,/ , $list[$i]); %temphash = (%temphash, ($data[0] => $data[1]) ); } open (STOCKLIST, ">stocklist.csv") || die ("Could not open file. $!"); foreach my $key (sort keys %temphash) { print STOCKLIST "$key,$temphash{$key}"; } print STOCKLIST $list[$#list]; close (STOCKLIST); &fini; } else { $done = 1; } } until $done; } #------------------------------------------------------------------ # Updates scrips with Data from NSE - Not valid for NCDEX/MCX #------------------------------------------------------------------ sub updatequote { if (defined($end) && (length($end)>9)) { #Open stocklist for obtaining symbol and end-date for updation open (STOCKLIST, "; close (STOCKLIST); #Progress Bar value $value_new = 100/$#list; #Update stocks one by one for(my $i=0;$i<$#list;$i++) { #Splitting the symbol and dates @quoteargs = split(/,/, $list[$i]); chomp($quoteargs[1]); #Gather data from the stocklist file to obtain start date for updation if ($quoteargs[1] ne "NA") { #Data is present in the file - Hence take the latest value $start = $quoteargs[1]; } else { #Fresh file is being opened - Hence default value of 1-Jan-2004 is being used $start = "1-Jan-2004"; } #This will be the file for stock data $data="$quoteargs[0].csv"; #Update the Progress bar $percent_done = $value_new*($i+1); $MW->update; #Call the update procedure if ($start ne $end) { "e; $hlist->itemCreate($i, 1, -text => $end); } } # show the dialog $upd_compl_dialog->Show; #Reset the ProgressBar to zero $percent_done = 0; $MW->update(); } } #------------------------------------------------------------------ # Fetches Data from NSE - Not valid for NCDEX/MCX #------------------------------------------------------------------ sub quote { use Switch; #open the data file corresponding to the stock being updated- the file is created if it does not exist open (STOCKDATA, "+>>$data") || die ("Could not open file. $!"); close (STOCKDATA); open (STOCKDATA, "<$data") || die ("Could not open file. $!"); @test=; close (STOCKDATA); #Collect the arguments from the array - array is populated by the updatequote procedure $symbol = $quoteargs[0]; #Split the DD-MON-YYY format @start = split(/-/, $start); @end = split(/-/, $end); #map Start MON to MM for NSE format #Modification for Ver0.211 if(uc($start[1]) eq "JAN") { $a = 1; } elsif (uc($start[1]) eq "FEB") { $a = 2; } elsif (uc($start[1]) eq "MAR") { $a = 3; } elsif (uc($start[1]) eq "APR") { $a = 4; } elsif (uc($start[1]) eq "MAY") { $a = 5; } elsif (uc($start[1]) eq "JUN") { $a = 6; } elsif (uc($start[1]) eq "JUL") { $a = 7; } elsif (uc($start[1]) eq "AUG") { $a = 8; } elsif (uc($start[1]) eq "SEP") { $a = 9; } elsif (uc($start[1]) eq "OCT") { $a = 10; } elsif (uc($start[1]) eq "NOV") { $a = 11; } elsif (uc($start[1]) eq "DEC") { $a = 12; } #map End MON to MM for NSE format if(uc($end[1]) eq "JAN") { $d = 1; } elsif (uc($end[1]) eq "FEB") { $d = 2; } elsif (uc($end[1]) eq "MAR") { $d = 3; } elsif (uc($end[1]) eq "APR") { $d = 4; } elsif (uc($end[1]) eq "MAY") { $d = 5; } elsif (uc($end[1]) eq "JUN") { $d = 6; } elsif (uc($end[1]) eq "JUL") { $d = 7; } elsif (uc($end[1]) eq "AUG") { $d = 8; } elsif (uc($end[1]) eq "SEP") { $d = 9; } elsif (uc($end[1]) eq "OCT") { $d = 10; } elsif (uc($end[1]) eq "NOV") { $d = 11; } elsif (uc($end[1]) eq "DEC") { $d = 12; } #Debug message - for runtime Verification print "Input Data: Stock =>".$symbol." Start =>".$start." End =>".$end."\n"; ##--------------------------------- # Modification for Ver0.211 # Data source is NSE ##--------------------------------- my $scrip = $symbol; my $Fromday = $start[0]; my $Frommon = $a; my $Fromyr = $start[2]; my $Today = $end[0]; my $Tomon = $d; my $Toyr = $end[2]; print "In LwpPost"; my $browser = LWP::UserAgent->new; $browser->env_proxy; my $response = $browser->post( 'http://www.nseindia.com/marketinfo/equities/scripvol/histscrip.jsp', [ 'inputtext' => $scrip, 'series' => 'EQ', 'ser' => 'EQ' , 'Fromday' => $Fromday, 'Frommon' => $Frommon, 'Fromyr' => $Fromyr, 'Today' => $Today, 'Tomon' => $Tomon, 'Toyr' => $Toyr, 'check' => 'new', ], ); die "Error: ", $response->status_line unless $response->is_success; my $eurl = 'http://www.nseindia.com/content/equities/scripvol/datafiles/'.$Fromday.$Frommon.$Fromyr.$Today.$Tomon.$Toyr.$scrip.'EQN.csv'; print $eurl; #Get the data from the LWP UserAgent $response = $browser->get( $eurl ); #Verify if operation was a success die "Can't get $eurl -- ". $response->status_line unless $response->is_success; ##--------------------------------- # End of Modifications for Ver0.211 # Data source is NSE ##--------------------------------- #verify if the file has already been populated if ($#test>1) { #file contains data. Hence take out init data , strip out last line and append with new data #Open the file in read mode and get data open (STOCKDATA, "<$data") || die ("Error: Could not open file - $!"); #Debug / verify message print "Found existing data for this scrip"; @init=; close (STOCKDATA); #Re-write existing data removing the last line #Open the file in overwrite mode and write down the updated stock info open (STOCKDATA, ">$data") || die ("Could not open file. $!"); #Put the csv content into $all $all = $response->content; #Split $all line by line @all = split(/\n/, $all); print STOCKDATA ($init[0]); #Rewrite from last to 2nd line for($i = $#all; $i > 1; $i--) { # For Ver 0.211 , data needs to be reordered # Required : Date, Open, High, Low, Close, Volume, Adj. Close # Present : Symbol, Series, Date, Prev Close, Open, High, Low, Close, Total Traded Qty, Turnover in Lacs # 0,1,2,3,4,5,6,7,8,9,10 ==> 3, 5, 6, 7, 8, 9, * my @allFields = split(/,/, $all[$i]); # Last field is left as 0. Retaining it for format compatibility reasons my $requiredFields = $allFields[2].','.$allFields[4].','.$allFields[5].','.$allFields[6].','.$allFields[7].','.$allFields[8].',0'; print STOCKDATA ($requiredFields."\n"); } for($i = 1; $i<=$#init; $i++) { print STOCKDATA ($init[$i]); } } else { #file is fresh open (STOCKDATA, ">$data") || die ("Error: Could not open file - $!"); #Put the csv content into $all $all = $response->content; #Split $all line by line @all = split(/\n/, $all); my @allFields = split(/,/, $all[0]); # Last field is left as 0. Retaining it for format compatibility reasons my $requiredFields = $allFields[2].','.$allFields[4].','.$allFields[5].','.$allFields[6].','.$allFields[7].','.$allFields[8].',0'; print STOCKDATA ($requiredFields."\n"); #Write from last to 2nd line for($i = $#all; $i > 0; $i--) { # For Ver 0.211 , data needs to be reordered # Required : Date, Open, High, Low, Close, Volume, Adj. Close # Present : Symbol, Series, Mkt type, Date, Prev Close, Open, High, Low, Close, Total Traded Qty, Turnover in Lacs # 0,1,2,3,4,5,6,7,8,9,10 ==> 3, 5, 6, 7, 8, 9, * my @allFields = split(/,/, $all[$i]); # Last field is left as 0. Retaining it for format compatibility reasons my $requiredFields = $allFields[2].','.$allFields[4].','.$allFields[5].','.$allFields[6].','.$allFields[7].','.$allFields[8].',0'; print STOCKDATA ($requiredFields."\n"); } print STOCKDATA "Elevetrica 2006\n"; } close (STOCKDATA); #write updation info into stocklist file - doubt whether previous handle can be reused - hence reopening file open (STOCKLIST, "; close (STOCKLIST); #Re-write stocklist info replacing the date for stock being updated open (STOCKLIST, ">stocklist.csv") || die ("Could not open file. $!"); for(my $i=0;$i<$#list;$i++) { my @listdata = split(/,/, $list[$i]); if ($listdata[0] eq $symbol) { $list[$i] = $listdata[0].",".$end."\n"; } print STOCKLIST $list[$i]; } #End remark for stocklist print STOCKLIST "\n"; close (STOCKLIST); $hlist->update(); $MW->update; }#End of procedure 'quote' #------------------------------------------------------------------ # Added this to remove the List:Util module include #------------------------------------------------------------------ sub Max { # takes an array ref - returns the max my $list = shift; my $max = $list->[0]; foreach (@$list) { $max = $_ if ($_ > $max); } return($max); } #------------------------------------------------------------------ # Added this to remove the List:Util module include #------------------------------------------------------------------ sub Min { # takes an array ref - returns the min my $list = shift; my $min = $list->[0]; foreach (@$list) { $min = $_ if ($_ < $min); } return($min); } #------------------------------------------------------------------------------ # This function returns number of lines as specified in the # global var $GLOBAL_POINT_COUNT. # NOTE: Each session may change its $GLOBAL_POINT_COUNT depending onthe requirement #------------------------------------------------------------------------------ sub getDataLines() { if ($#_ < $GLOBAL_POINT_COUNT || $GLOBAL_POINT_COUNT >= 300000) { return @_; } else { my @trimmedArray = (); for my $i (0 .. $GLOBAL_POINT_COUNT) { $trimmedArray[$i] = $_[$i]; } return @trimmedArray; } }