html/stocks.pl


   1 #!/usr/bin/env perl
   2 
   3 use strict;
   4 use LWP::Simple;
   5 use Irssi;
   6 use vars qw($VERSION %IRSSI);
   7 use HTML::Entities;
   8 
   9 $VERSION = '0.9';
  10 %IRSSI = (
  11     authors     => 'Marcus \'darix\' Rückert, tira, Stefan \'tommie\' Tomanek',
  12     contact     => 'darix@irssi.de, tira@isx.de, stefan@pico.ruhr.de',
  13     name        => 'stocks',
  14     description => 'prints the stats for german stocks',
  15     license     => 'Public Domain',
  16     url         => 'http://irssi.org/scripts/',
  17     sbitems     => 'stocks_ticker'
  18 );
  19 
  20 my %stocklist = (
  21     DE => 'FSE+DTB+MUN+HAM+HAN+BRE+STU+BER+ETR+DUS+FFM+FFI+FFK+FFC+DFK+FFT',
  22     EU =>
  23 'LIF+LCE+MSE+MAT+LME+NLK+ZRH+SFF+EOE+ROT+MEE+MIF+BBA+PSE+ASX+BSE+MSX+HSE+MIX+ISE+WSE+KSX+SSE+OSX+ENM+POP+BAS+BRN+MOP+SQ2+LTO+PAB+ISS+SQ1+ATH+LIS+LUX',
  24     OTHERS =>
  25 'FX1+IPE+CSC+FNX+TSE+PAR+TYO+OPR+IMM+FFX+IOM+SMX+HFE+TOR+TIF+OSE+MRF+MRV+TFE+TOC+BIS+TGE+CSH+ICP+NXC+IMC+CBC+HOX+OPA+CBQ+SON+MAS+RDW+BHL+AUS+SSW+ALB+COC+TOE+VSE+CBF+NAT+MBF+TWI+TGT',
  26     US =>
  27 'NYS+IND+NAS+CBT+CME+KBT+WPG+NYC+NYM+CMX+NYF+SFE+MIN+ASE+MAC+CEC+FOX+FRE+DOA+BOE+NAP',
  28     ASE => 'ASE',
  29     ASX => 'ASX',
  30     ATH => 'ATH',
  31     BER => 'BER',
  32     BRE => 'BRE',
  33     BSE => 'BSE',
  34     C05 => 'C05',
  35     CBT => 'CBT',
  36     CME => 'CME',
  37     DFK => 'DFK',
  38     DTB => 'DTB',
  39     DUS => 'DUS',
  40     ENM => 'ENM',
  41     ETR => 'ETR',
  42     FFC => 'FFC',
  43     FFI => 'FFI',
  44     FFM => 'FFM',
  45     FFT => 'FFT',
  46     FSE => 'FSE',
  47     FX1 => 'FX1',
  48     HAM => 'HAM',
  49     HAN => 'HAN',
  50     IND => 'IND',
  51     ISE => 'ISE',
  52     ISS => 'ISS',
  53     MIX => 'MIX',
  54     MUN => 'MUN',
  55     NAP => 'NAP',
  56     NAS => 'NAS',
  57     NYS => 'NYS',
  58     PAR => 'PAR',
  59     PSE => 'PSE',
  60     SFF => 'SFF',
  61     SON => 'SON',
  62     SQ1 => 'SQ1',
  63     SQ2 => 'SQ2',
  64     SSE => 'SSE',
  65     STU => 'STU',
  66     TGT => 'TGT',
  67     TWI => 'TWI',
  68     WSE => 'WSE',
  69     ZRH => 'ZRH'
  70 );
  71 
  72 my %stockhelp = (
  73     DE =>
  74 'Deutschland (FSE DTB MUN HAM HAN BRE STU BER ETR DUS FFM FFI FFK FFC DFK FFT)',
  75     EU =>
  76 'Europa (LIF LCE MSE MAT LME NLK ZRH SFF EOE ROT MEE MIF BBA PSE ASX BSE MSX HSE MIX ISE WSE KSX SSE OSX ENM POP BAS BRN MOP SQ2 LTO PAB ISS SQ1 ATH LIS LUX)',
  77     OTHERS =>
  78 'Andere (FX1 IPE CSC FNX TSE PAR TYO OPR IMM FFX IOM SMX HFE TOR TIF OSE MRF MRV TFE TOC BIS TGE CSH ICP NXC IMC CBC HOX OPA CBQ SON MAS RDW BHL AUS SSW ALB COC TOE VSE CBF NAT MBF TWI TGT)',
  79     US =>
  80 'USA (NYS IND NAS CBT CME KBT WPG NYC NYM CMX NYF SFE MIN ASE MAC CEC FOX FRE DOA BOE NAP)',
  81     ASE => 'AMEX',
  82     ASX => 'Amsterdam',
  83     ATH => 'Athen',
  84     BER => 'Berlin',
  85     BRE => 'Bremen',
  86     BSE => 'Brüssel',
  87     C05 => 'LiveTrading',
  88     CBT => 'CBoT',
  89     CME => 'CME',
  90     DFK => 'Fonds DE',
  91     DTB => 'EUREX',
  92     DUS => 'Düsseldorf',
  93     ENM => 'EURO.NM',
  94     ETR => 'XETRA',
  95     FFC => 'Frankfurt',
  96     FFI => 'FFM Indizes 2',
  97     FFM => 'FFM Indizes 1',
  98     FFT => 'Frankfurt STOXX',
  99     FSE => 'Frankfurt',
 100     FX1 => 'FOREX',
 101     HAM => 'Hamburg',
 102     HAN => 'Hannover',
 103     IND => 'USA Indizes',
 104     ISE => 'London',
 105     ISS => 'London Inl.',
 106     MIX => 'Mailand',
 107     MUN => 'München',
 108     NAP => 'Nasdaq OTC',
 109     NAS => 'Nasdaq',
 110     NYS => 'NYSE',
 111     PAR => 'Int. Indizes',
 112     PSE => 'Paris',
 113     SFF => 'SOFFEX',
 114     SON => 'Sonderwerte',
 115     SQ1 => 'London Auslandsak.',
 116     SQ2 => 'London Auslandsak.',
 117     SSE => 'Stockholm',
 118     STU => 'Stuttgart',
 119     TGT => 'TD GT',
 120     TWI => 'TD Indizes',
 121     WSE => 'Wien',
 122     ZRH => 'Zürich'
 123 );
 124 
 125 my %WPArt = (
 126     STK => 'Aktie',
 127     BND => 'Anleihe',
 128     FND => 'Fonds',
 129     FUT => 'Future',
 130     IND => 'Index',
 131     OPT => 'Option',
 132     WNT => 'Optionsschein',
 133     OTC => 'Over The Counter',
 134     MSC => 'Sonstige',
 135     SPC => 'Sonderwert',
 136     CUR => 'Währung',
 137     RTE => 'Zinssatz'
 138 );
 139 
 140 # search
 141 #  -boerse {eu|de|us|others|}
 142 
 143 sub cmd_kurs {
 144     my $XsearchWPArt   = 'UKN';
 145     my $XsearchBoersen = 'UKN';
 146     my $params         = shift ();
 147 
 148     if ( $params =~ m/-help/ ) {
 149         if ( $params =~ m/stocks/ ) {
 150             Irssi::print( "\cBhelp for stocks\cB", MSGLEVEL_CRAP );
 151             foreach my $key ( sort keys %stockhelp ) {
 152                 Irssi::print( "$key - $stockhelp{$key}", MSGLEVEL_CRAP );
 153             }
 154         }
 155         else {
 156             if ( $params =~ m/bonds/ ) {
 157                 Irssi::print( "\cBhelp for kind of bonds\cB", MSGLEVEL_CRAP );
 158                 foreach my $key ( sort keys %WPArt ) {
 159                     Irssi::print( "$key - $WPArt{$key}", MSGLEVEL_CRAP );
 160                 }
 161             }
 162             else {
 163                 Irssi::print(
 164 "\cBSTOCKS\cB [-stocks <stocklist>] [-bonds <wplist>] <querysting>",
 165                     MSGLEVEL_CRAP
 166                 );
 167                 Irssi::print( "",                    MSGLEVEL_CRAP );
 168                 Irssi::print( "\cBSee also:\cB",     MSGLEVEL_CRAP );
 169                 Irssi::print( "  STOCKS -help stocks", MSGLEVEL_CRAP );
 170                 Irssi::print( "  STOCKS -help bonds",     MSGLEVEL_CRAP );
 171             }
 172         }
 173         return;
 174     }
 175 
 176     while ( $params =~ m/-(\S+) (\S+)/ ) {
 177 
 178         #    Irssi::print($2." ".$3, MSGLEVEL_CRAP);
 179         my $vars   = $2;
 180         my $option = $1;
 181         if ( $option eq "stocks" ) {
 182             my @stocks = split ( ',', $vars );
 183             for my $stock (@stocks) {
 184                 if ( exists $stocklist{$stock} ) {
 185                     $stock = $stocklist{$stock};
 186                 }
 187                 else {
 188                     Irssi::print( "stock $stock does not exists see /STOCKS -help stocks",
 189                         MSGLEVEL_CRAP );
 190                     return;
 191                 }
 192             }
 193             $XsearchBoersen = join ( "+", @stocks );
 194         }
 195         else {
 196             if ( $option eq "bonds" ) {
 197                 my @wps = split ( ',', $vars );
 198                 for my $wp (@wps) {
 199                     if ( !exists $WPArt{$wp} ) {
 200                         Irssi::print( "Kind of bond $wp does not exists see /STOCKS -help bonds",
 201                             MSGLEVEL_CRAP );
 202                         return;
 203                     }
 204                 }
 205                 $XsearchWPArt = join ( "+", @wps );
 206             }
 207             else {
 208                 Irssi::print( "unknown option $option see /STOCKS -help", MSGLEVEL_CRAP );
 209                 return;
 210             }
 211         }
 212         $params =~ s/-(\S+) (\S+)//;
 213     }
 214     $params =~ s/\^s+//;
 215 
 216     #  Irssi::print($XsearchBoersen, MSGLEVEL_CRAP);
 217     #  Irssi::print($XsearchWPArt, MSGLEVEL_CRAP);
 218     #  Irssi::print($params, MSGLEVEL_CRAP);
 219     if ( $params eq "" ) {
 220         Irssi::print( "empty query string see /STOCKS -help", MSGLEVEL_CRAP );
 221         return;
 222     }
 223     my $searchfor = $params;
 224     $searchfor =~ s/ /\%20/g;
 225     my $host         = "http://informer2.comdirect.de";
 226     my $path         = '/de/suche/main.html?';
 227     my $searchButton = 'Exakt';
 228     my $querystring  =
 229 "&searchButton=$searchButton&XsearchWPArt=$XsearchWPArt&XsearchBoersen=$XsearchBoersen&searchfor=$searchfor";
 230     
 231     my $content = get( $host . $path . $querystring );
 232 
 233     my ( $oldcompany, $comp, $nbr, $boerse ) = "";
 234 
 235     $searchfor =~ s/\%20/ /g;
 236 
 237     if ( $content =~ m/Suchbegriff/s ) {
 238         if ( $content =~ m/Kurszeit/ ) {
 239             Irssi::print( "\cB" . $searchfor . " found:\cB", MSGLEVEL_CRAP );
 240             $content =~ s/\&nbsp//g;
 241             $content =~ m/Kurszeit.*?<\/tr>(.*?)<\/table>/s;
 242             $content = $1;
 243             while ( $content =~
 244 m/<td.*?>(.*?)<\/td>.*?<td.*?>(.*?)<\/td>.*?<td.*?>(.*?)<\/td>.*?<td.*?>(.*?)<\/td>.*?/s
 245               )
 246             {
 247                 $comp   = $1;
 248                 $nbr    = $3;
 249                 $boerse = $2;
 250                 decode_entities($comp);
 251                 decode_entities($nbr);
 252                 decode_entities($boerse);
 253                 if ($comp) {
 254                     Irssi::print( "  " . $nbr . " " . $boerse . ": " . $comp,
 255                         MSGLEVEL_CRAP );
 256                     $oldcompany = $comp;
 257                 }
 258                 else {
 259                     Irssi::print(
 260                         "  " . $nbr . " " . $boerse . ": " . $oldcompany,
 261                         MSGLEVEL_CRAP );
 262                 }
 263                 $content =~ m/<tr.*?>.*?<\/tr>(.*)/s;
 264                 $content = $1;
 265             }
 266         }
 267         else {
 268             Irssi::print( "\cBcould not find:\cB $searchfor", MSGLEVEL_CRAP );
 269         }
 270         return;
 271     }
 272 
 273     if ( $content =~
 274 m/<th width="99%" class="news">(.*?)<\/th>.*?<td.*?>WKN.*?class="sym">(\d+)/s
 275       )
 276     {
 277         Irssi::print( "\c_WKN " . $2 . " - " . $1 . "\c_", MSGLEVEL_CRAP );
 278     }
 279 
 280     if ( $content =~ m/<td.*?>(Aktueller Kurs)<\/td>\s+<td>(.*?)<\/td>/s ) {
 281         Irssi::print( "  \cB" . $1 . ":\cB " . $2, MSGLEVEL_CRAP );
 282     }
 283 
 284     if ( $content =~ m/<td.*?>R&uuml;cknahmepreis<\/td>\s+<td>(.*?)<\/td>/s ) {
 285         Irssi::print( "  \cBRücknahmepreis:\cB " . $1, MSGLEVEL_CRAP );
 286     }
 287 
 288     if ( $content =~ m/<td.*?>(Ausgabepreis)<\/td>\s+<td>(.*?)<\/td>/s ) {
 289         Irssi::print( "  \cB" . $1 . ":\cB " . $2, MSGLEVEL_CRAP );
 290     }
 291 
 292     if ( $content =~ m/<td.*?>(Differenz)<\/td>\s+<td>(.*?)<\/td>/s ) {
 293         Irssi::print( "  \cB" . $1 . ":\cB " . $2, MSGLEVEL_CRAP );
 294     }
 295 }
 296 
 297 
 298 # added by Stefan 'tommie' Tomanek
 299 use vars qw{$ticker_shift $ticker_text $update_tag $refresh_tag};
 300 
 301 sub get_stock {
 302     my ($wkn, $exchange) = @_;
 303 
 304     my $XsearchWPArt   = 'STK';
 305     my $XsearchBoersen = $exchange;
 306     
 307     my $searchfor = $wkn;
 308     #$searchfor =~ s/ /\%20/g;
 309     my $host         = "http://informer2.comdirect.de";
 310     my $path         = '/de/suche/main.html?';
 311     my $searchButton = 'Exakt';
 312     my $querystring = "&searchfor=".$wkn."&searchButton=Exakt&XsearchWPArt=STK&XsearchBoersen=".$exchange;
 313 
 314     my $content = get( $host . $path . $querystring );
 315 
 316     my ( $oldcompany, $comp, $nbr, $boerse ) = "";
 317 
 318     my %stock;
 319     if ( $content =~
 320 m/<th width="99%" class="news">(.*?)<\/th>.*?<td.*?>WKN.*?class="sym">(\d+)/s
 321       )
 322     {
 323 	$stock{'wkn'} = $2;
 324 	$stock{'company'} = $1;
 325     }
 326 
 327     if ( $content =~ m/<td.*?>(Aktueller Kurs)<\/td>\s+<td>(.*?)<\/td>/s ) {
 328 	$stock{'price'} = $2;
 329 	$stock{'price'} =~ s/&nbsp;<small>.*<\/small>//;
 330     }
 331     if ( $content =~ m/<td.*?>(Differenz)<\/td>\s+<td>(.*?)<\/td>/s ) {
 332 	$stock{'diff'} = $2;
 333     }
 334     return %stock;
 335 }
 336 
 337 sub update_ticker {
 338     fork_get();
 339 }
 340 
 341 sub fork_get {
 342     my ($rh, $wh);
 343     pipe($rh, $wh);
 344     my $pid = fork();
 345     if ($pid > 0) {
 346 	close $wh;
 347 	Irssi::pidwait_add($pid);
 348 	my $pipetag;
 349 	my @args = ($rh, \$pipetag);
 350 	$pipetag = Irssi::input_add(fileno($rh), INPUT_READ, \&pipe_input, \@args);
 351     } else {
 352 	eval {
 353 	    my $data = get_ticker_data();
 354 	    print($wh $data);
 355 	    close($wh)
 356 	};
 357 	POSIX::_exit(1);
 358     }
 359 }
 360 
 361 sub pipe_input ($) {
 362     my ($rh, $pipetag) = @{$_[0]};
 363     my @lines = <$rh>;
 364     close($rh);
 365     Irssi::input_remove($pipetag);
 366     my $text = join("", @lines);
 367     $ticker_text = $text;
 368 }
 369 
 370 sub shift_string {
 371     my ($string, $pos) = @_;
 372     my $first = substr($string, 0, $pos);
 373     my $middle = substr($string, $pos);
 374     return $middle.$first;
 375 }
 376 
 377 $ticker_shift = 0;
 378 sub show_ticker {
 379     my ($item, $get_size_only) = @_;
 380     my $ticker_string = $ticker_text;
 381     unless ($get_size_only) {
 382         $ticker_shift = 0 if ($ticker_shift >= length($ticker_string));
 383     }
 384     my $max_width = Irssi::settings_get_int('stocks_ticker_max_width');
 385     my $ticker_text = shift_string($ticker_string, $ticker_shift);
 386     $ticker_text = substr($ticker_text, 0, $max_width-3) if (length($ticker_text)+2 > $max_width);
 387     $item->{min_size} = $item->{max_size} = length("$ticker_text")+2;
 388     $ticker_text =~ s/\%/\%\%/g;
 389     $ticker_text = '>'.$ticker_text.'%n>';
 390     $ticker_text =~ s/\(\-/\%R\(\-/g;
 391     $ticker_text =~ s/\(\+/\%G\(\+/g;
 392     $ticker_text =~ s/\)/\)\%n/g;
 393     my $format = "{sb ".$ticker_text."}";
 394     $item->default_handler($get_size_only, $format, 0, 1);
 395 }
 396 
 397 sub ticker_redraw {
 398     $ticker_shift++;
 399     Irssi::statusbar_items_redraw('stocks_ticker');
 400 }
 401 
 402 sub get_ticker_data {
 403     my @stocks = split(/,/, Irssi::settings_get_str('stocks_ticker_stocks'));
 404     my $tape='';
 405     foreach (@stocks) {
 406 	my ($wkn, $exchange, $name) = split(/\//, $_);
 407 	my %stock = get_stock($wkn, $exchange);
 408 	if ($name eq '') { $name = $stock{'company'}; };
 409 	$tape = $tape.'| '.$name.': '.$stock{'price'}.'/'.$stock{'diff'};
 410     }
 411     return $tape;
 412 }
 413 
 414 sub load_config {
 415     Irssi::timeout_remove($update_tag);
 416     Irssi::timeout_remove($refresh_tag);
 417     $update_tag = Irssi::timeout_add(Irssi::settings_get_int('stocks_ticker_update_delay'), 'update_ticker', undef);
 418     $refresh_tag = Irssi::timeout_add(Irssi::settings_get_int('stocks_ticker_scroll_delay'), 'ticker_redraw', undef);
 419     update_ticker();
 420 }
 421 
 422 Irssi::statusbar_item_register('stocks_ticker', 0, 'show_ticker');
 423 Irssi::settings_add_int('misc', 'stocks_ticker_max_width', 20);
 424 Irssi::settings_add_int('misc', 'stocks_ticker_update_delay', 120000);
 425 Irssi::settings_add_int('misc', 'stocks_ticker_scroll_delay', 2000);
 426 Irssi::settings_add_str('misc', 'stocks_ticker_stocks', '');
 427 
 428 Irssi::command_bind( 'stocks', 'cmd_kurs' );
 429 Irssi::command_bind( 'stocks_ticker_update', 'load_config' );
 430 
 431 load_config();