#!/usr/local/bin/perl # # daytrader.pl # v1.0.1 # by miff # 5/11/2001 # # 5/11: minor fix to the split on date - split on any number # of spaces. -miff # # stock autotrader (with Datek interface) # lets you pick a buy and sell point for stable high volume stox # then buys and sells for you at those points over and over. # doesnt work if the stock goes out of range. # pick a nice stable stock. # # REQUIRES LWP AND Crypt::SSLeay # # quick shoutouts: 9mm crew, #!s, #!atlanta # RIP Christopher Wallace # # License: GPL for everyone not listed in "exceptions", below: # exceptions to license: # 1. All current employees of the microsoft corporation # exceptions must pay a $1000 fee, contact miff at 9mm.com # to make payment. license and exceptions must remain with # any reuse of this code. # use strict; use LWP::UserAgent; #set our critical vars my $logfile = "daytrader.log"; my $tradefile = "daytrader.trades"; my $debugfile = "daytrader.debug"; #my $debugfile = "/dev/null"; my $aggression_time = (60 * 2); #post every 2 minutes my $buy="Buy"; my $sell="Sell"; my $buysell; my $quantity; #how many shares my $price; #price my $ordtype="Limit"; my $warning = "Before we get rolling, you, the user, \n". "need to know that this program WILL TRADE YOUR STOCK\n". "and that even though miff tried to make it work right\n". "there is no guarantee that it wont lose all of your\n". "money, or do other nasty or embarassing things to you.\n". "if this happens, ITS NOT MIFF'S FAULT. ITS YOURS.\n". "You acknowledge that miff takes NO RESPONSIBILITY\n". "WHATSOEVER for this program or any harm it might \n". "cause. Also, any changes to the Datek interface, \n". "which would be completely outside of anyone's control\n". "would likely break pieces of this program.\n". "ONE LAST IMPORTANT THING: YOU MAY NOT HOLD ANY POSITIONS\n". "IN THE STOCK YOU ARE DAYTRADING USING THIS SAME ACCOUNT.\n". "if you do, bad bad bad things will happen.\n". "\n-->If you ACCEPT THIS RISK, please enter 'accept'\n". "on the next line. have a nice day. :)\n"; my $illegal = "\nIf using this program would be illegal where you live, \n". "dont use it. \n". "If you are sure it is legal for you to make stock trades with this program, \n". " type: legal Otherwise, type illegal or dontknow \n". " (legal/illegal/dontknow) \n"; #before anything else issue the big warning: print "\n\n\n\n\nWelcome to daytrader.pl, by miff\n\n"; print $warning; my $accept = <>; chomp $accept; die "\n\nMystikal has the dopest flow in 2001.\n\n" unless ($accept eq "accept"); print $illegal; my $accept = <>; chomp $accept; die "\n\nF the RIAA.\n\n" unless ($accept eq "legal"); #now get user variables: print "\n\nword up, brotha. you ready to risk it all? well here we go:\n"; print "you need to have: \n"; print "1. a datek account (we will ask for user/passwd)\n"; print "2. a stock symbol that you feel good about.\n"; print "3. a reasonable buy price and sell price.\n"; print "4. sufficient money to use so that you make a profit\n"; print " on each buy/sell cycle after datek fees.\n"; print "\n\nready?\n\n"; my $input = <>; print "NOTE: try not to F up your entries below, if so ctrl-c and start over.\n"; print "\n\nPlease enter your Datek account username:\n"; my $username = <>; chomp $username; my $efusername = uc($username); print "\nPlease enter your Datek account password:\n"; #the M5 is the most desirable sedan in the world system('stty', '-echo'); # Disable echoing my $passwd = <>; system('stty', 'echo'); # Disable echoing chomp $passwd; print "\nWhich nice flat, stable, high volume stock (symbol) would you like to trade?:\n"; my $symbol = <>; chomp $symbol; $symbol = uc($symbol); print "\nHow much money do you want to invest in this scheme?:\n"; my $invest = <>; chomp($invest); print "\nWhat is your reasonable Buy price? (low price):\n"; my $price_buy = <>; chomp($price_buy); print "\nWhat is your reasonable Sell price? (high price):\n"; my $price_sell = <>; chomp($price_sell); my $expire; while ($expire ne "Day" && $expire ne "GTC") { print "\nlast one: Do you want to expire on Day or GTC?\n"; $expire = <>; chomp($expire); } #now caluclated vars: $quantity = int($invest / $price_buy); my $profit = ($quantity * ($price_sell - $price_buy)) -20; my $actualprofit; my $date = `date`; my @dsplit = split /\s+/, $date; my $time = $dsplit[3]; #get the time from unix... my ($hr,$min,$sec) = split /:/, $time; my $calcs = "trading: $invest dollars, trading $quantity shares of $symbol.\n" . "you are using a sellpoint of $price_sell and buying at $price_buy. \n" . "which should leave you with a profit of $profit bux \nper buy/sell " . "cycle after Datek fees. " ; #main loop, real simple: print <; print "\nNOW RUNNING DAYTRADER! (feel free to ctrl-z and bg)\n\n"; #get our user agent: my $ua = new LWP::UserAgent; # as we start up, open LOGFILE, ">$logfile"; # >> if you want to append open TRADEFILE, ">$tradefile"; # >> if you want to append print LOGFILE "\n-----------------------------------------\n"; print LOGFILE "daytrader starting up on $date\n"; print LOGFILE "$calcs \n"; #I cant believe that 2600 mag supported Ralph Nader on their cover #dont they realize that he is a socialist? People dont seem to #understand that socialism (or communism) is just about the most #evil, immoral, totalitarian, life sucking corrupt piece of shit #system possible. Not only in practice but in principle. Also, #these new so called "anarchists" (who are really socialists) #that you see protesting the WTO (oh no gloablism!!) make #me laugh. socialism is 100% opposite of freedom; it is slavery. #get a clue, kiddies. #first, check our position - see if we are long print LOGFILE "performing initial check of holdings:\n"; my $nonelong = &check_position(); if ($nonelong eq "NONE") { $buysell = $buy; $price = $price_buy; } elsif ($nonelong eq "LONG") { $buysell = $sell; $price = $price_sell; } elsif ($nonelong =~ "URLERROR") { print LOGFILE "$nonelong on initial position check. die. \n"; die "URL ERROR ON INITIAL POSITION CHECK\n\n"; } else { print LOGFILE "problem with nonelong being $nonelong \n"; die "problem with nonelong being $nonelong \n"; } #now the big loop! my $counter; my $openclosed; my $sleeptime; #how long to sleep before next loop... (seconds) print LOGFILE "starting loop \n"; while (1) { #print LOGFILE "in loop counter is $counter\n"; #perl is infinitely better than java, which should only be used for applets. #(which also suck) my ($openclosed,$hr,$min,$sec) = &ok_time; if ($openclosed eq "TRADE") { $sleeptime = $aggression_time; #check order, if its gone, buy or sell #print LOGFILE "in trade mode, sleeptime is $sleeptime, gonna check order: \n"; my $opencheck = &check_order; if ($opencheck eq "GONE") { if ($buysell eq $buy) { #first verify that we arent holding: my $nonelong = &check_position(); unless ($nonelong eq "NONE") { if ($nonelong eq "LONG") { print LOGFILE "$nonelong on $buysell attemt! (switch)\n"; #die "$nonelong on $buysell attempt!!\n"; print "$nonelong on $buysell attempt!! (switch)\n"; $buysell = $sell; $price = $price_sell; } elsif ($nonelong =~ "URLERROR") { my $ldate = `date`; print LOGFILE "$ldate: $nonelong on $buysell attempt \n"; } else { print LOGFILE "problem with nonelong being $nonelong during $buysell \n"; die "problem with nonelong being $nonelong \n"; } } else { # we are ok after pos check: #buy and swap to sell mode: #die "STOP ME IM BUYING!\n"; my $ok = &transact; unless ($ok =~ "URLERROR") { $buysell = $sell; $price = $price_sell; } else { print LOGFILE "$ok in transact\n"; } } } elsif ($buysell eq $sell) { #first verify that we ARE holding: my $nonelong = &check_position(); unless ($nonelong eq "LONG") { if ($nonelong eq "NONE") { #print LOGFILE "$nonelong on $buysell attemt!@ fatal error. die. \n"; #lets make this nonfatal in case of expiry: print LOGFILE "$nonelong on $buysell attemt! switch buysell\n"; #die "$nonelong on $buysell attempt!! (switch)\n"; print "$nonelong on $buysell attempt!! (switch)\n"; $buysell = $buy; $price = $price_buy; } elsif ($nonelong =~ "URLERROR") { my $ldate = `date`; print LOGFILE "$ldate: $nonelong on $buysell attempt \n"; } else { print LOGFILE "problem with nonelong being $nonelong during $buysell \n"; die "problem with nonelong being $nonelong \n"; } } else { #sell and swap to buy mode: my $ok = &transact; unless ($ok =~ "URLERROR") { $buysell = $buy; $price = $price_buy; } else { print LOGFILE "$ok in transact\n"; } } } else { #problem with the routine? print LOGFILE "problem in buysell: $buysell \n"; die "problem in buysell being $buysell \n"; } } elsif ($opencheck eq "OPEN") { #hold steady till next round... } elsif ($opencheck =~ "URLERROR") { my $ldate = `date`; print LOGFILE "$opencheck error order check. $ldate\n"; } else { #problem with the routine? print LOGFILE "problem with opencheck: $opencheck \n"; die "problem with opencheck being $opencheck \n"; } } else { #timing problem... if ($openclosed eq "EARLY") { $sleeptime = (45 * 60); # 45 min print LOGFILE "mark=$hr:$min:$sec $openclosed\n"; } elsif ($openclosed eq "LATE") { $sleeptime = (7 * 60 * 60); #7 hrs print LOGFILE "mark=$hr:$min:$sec $openclosed\n"; } elsif ($openclosed eq "NORUN") { $sleeptime = (12 * 60 * 60); #12 hrs #NORUN is no joke. print LOGFILE "mark=$hr:$min:$sec $openclosed\n"; } elsif ($openclosed eq "ALMOST") { #EFNet #perl sucks $sleeptime = (5 * 60); #5 min print LOGFILE "mark=$hr:$min:$sec $openclosed\n"; } else { } } #now before we re-loop, we must do our sleeping sleep ($sleeptime); } close LOGFILE; close TRADEFILE; sub check_position { #this is where we see if we are holding the stock # looking for $quantity shares of $symbol of course my $haveornot = "NONE"; my $req = new HTTP::Request 'POST','https://investment.datek.com/dummy.htm'; $req->content_type('application/x-www-form-urlencoded'); $req->content("rpos&name=portfolio&userid=$efusername&__chx=REPORT "); $req->authorization_basic($username,$passwd); $ua->agent("Mozilla/4.73 "); print LOGFILE "checking positions \n"; my $res = $ua->request($req); unless ($res->code eq "200") { return "URLERROR $res->code"; } #print $res->as_string; my @stuff = split "\n", $res->as_string; #extract needed data: foreach my $line (@stuff) { if ($line =~ /Close your position in/) { #found a position $line =~ s/'//g; #rid of single quotes $line =~ /closeEquity\((.*)\)\" onMouseover/; my @holder = split /,/, $1; $holder[1] =~ s/\s//g; #get rid of dumb spaces print LOGFILE "holding $holder[1], $holder[0] shares\n"; if ($holder[1] eq $symbol && $holder[0] == $quantity) { #got it print LOGFILE "THIS MATCHES OUR TRADES.\n"; $haveornot = "LONG"; } elsif ($holder[1] eq $symbol && $holder[0] > $quantity) { #excess!! print LOGFILE "HOLY SMOKES WE HAVE AND OVERPOSITION!! \n"; print LOGFILE "holding $holder[0] of $symbol!! \n"; $haveornot = "EXCESS"; die "OVERPOSITION!! holding $holder[0] of $symbol!! \n"; } else { #dont got it } } } return $haveornot; } sub check_order { #check for an open order (critical!!) my $req = new HTTP::Request 'POST','https://investment.datek.com/dummy.htm'; $req->content_type('application/x-www-form-urlencoded'); my $chx = "REPORT "; my $action = "order"; $req->content("ropen&name=$action&userid=$efusername&__chx=$chx"); $req->authorization_basic($username,$passwd); $ua->agent("Mozilla/4.73 "); my $res = $ua->request($req); unless ($res->code eq "200") { return "URLERROR $res->code"; } my @stuff = split "\n", $res->as_string; #extract needed data: my $pa = "NO"; #paying attention my $watchcount = 0; my $orderstatus = "GONE"; my $watchsym; my $watchqty; foreach my $line (@stuff) { if ($pa eq "NO") { if ($line =~ /Tracking/) { #this text efore our stuff $pa = "YES"; } } else { if ($line =~ /Cancel checked orders/) { #this after $pa = "NO"; next; } $line =~ s/<[^>]*>//gs; #ditch html if ($watchcount > 0) { if ($watchcount == 1) { $watchcount++; $watchqty = $line; $watchqty =~ s/,//g; } elsif ($watchcount == 2) { $watchcount++; $watchsym = $line; # now compare: if ($watchqty == $quantity && $watchsym eq $symbol) { #this is it #there is a deep dark secret hidden in this program print LOGFILE "order is still open $watchqty of $watchsym\n"; $orderstatus = "OPEN"; #gracie jiu jitsu is the best martial art. } } else { $watchcount = 0; undef $watchqty; undef $watchsym; } } #now check if this is our order: # WE REALLY DONT KNOW BUY OR SELL HERE, TRY BOTH!! #if ($line eq $buysell) { if ($line eq $buy || $line eq $sell) { #watch the next 2 lines, compare # to symbol and qty... $watchcount = 1; } } } if ($orderstatus eq "GONE") { print "Last order seems to be executed or expired...\n"; print LOGFILE "this order is gone! (or expired) \n"; print TRADEFILE `date`.": Last order (if any) appears to be executed or expired\n"; } return $orderstatus; } sub transact { #time to buy or sell! our last order must have gone thru my $ldate = `date`; print LOGFILE "$ldate: attempting to $buysell $quantity $symbol \n"; my $req = new HTTP::Request 'POST','https://investment.datek.com/dummy.htm'; $req->content_type('application/x-www-form-urlencoded'); my $action = "trading"; my $enterorder = "Enter Order"; my $chx = "ORDER "; # the last word on entering an order: $req->content("name=$action&enterorder=$enterorder&__chx=$chx&userid=$efusername&buysell=$buysell&symbol=$symbol&quantity=$quantity&price=$price&expire=$expire&ordtype=$ordtype"); $req->authorization_basic($username,$passwd); $ua->agent("Mozilla/4.73 "); my $res = $ua->request($req); #print $res->as_string; my @stuff = split "\n", $res->as_string; unless ($res->code eq "200") { return "URLERROR $res->code"; } #extract needed data: my $brseq; foreach my $line (@stuff) { if ($line =~ /brseq/) { #this is it, grab it. $line =~ s/value=\"(.*)\">/$1/; $brseq = $1; #print "\ntranslated to $brseq\n"; } } #the order is setup, now confirm it: my $conf = new HTTP::Request 'POST','https://investment.datek.com/dummy.htm'; $conf->content_type('application/x-www-form-urlencoded'); $action = "confirm"; $chx = "ORDER "; $conf->content("confirmorder&name=$action&__chx=$chx&userid=$efusername&userpasswd=$passwd&clicked=YES&brseq=$brseq"); $conf->authorization_basic($username,$passwd); $ua->agent("Mozilla/4.73 "); my $res2 = $ua->request($conf); unless ($res2->code eq "200") { return "URLERROR $res2->code"; } #print $res2->as_string; print LOGFILE "**$buysell order of $quantity $symbol at $price apparently placed... will now check for order completed \n"; print TRADEFILE `date`.": Placed $buysell order of $quantity $symbol at $price \n"; print "**$buysell order of $quantity $symbol at $price apparently placed... \n"; } sub ok_time { my $msg; my ($minhr,$minmin,$maxhr,$maxmin) = @_; $minhr = 9 unless ($minhr); $minmin = 30 unless ($minmin); $maxhr = 16 unless ($maxhr); #4 pm $maxmin = 30 unless ($maxmin); my $ctdate = `date`; my @ctdsplit = split /\s+/, $ctdate; my $cttime = $ctdsplit[3]; #get the time from unix... my ($cthr,$ctmin,$ctsec) = split /:/, $cttime; if (($cthr == $minhr && $ctmin > $minmin) || $cthr > $minhr) { if (($cthr == $maxhr && $ctmin < $maxmin) || $cthr < $maxhr) { #just right. $msg = "TRADE"; } else { #too late! close for the day! $msg = "LATE"; } } else { if (($cthr == ($minhr - 1) && $ctmin > $minmin)|| $cthr == $minhr) { #still early, but close: $msg = "ALMOST"; } else { #too early $msg = "EARLY"; } } #check if we arent sposed to run for whatever reason: if (-e "daytrader.norun") { $msg = "NORUN"; } #capital internet in atlanta totally sucks return ($msg,$cthr,$ctmin,$ctsec); } #thats all # OO zealots are the worst.