Author

Topic: BT TRADER - MD Trader clone for Linux and Windows (Read 4917 times)

hero member
Activity: 566
Merit: 500
Unselfish actions pay back better
That's very weird, I have no idea what's happening here…
member
Activity: 135
Merit: 10
Quote
2011-06-28 23:53:33     closing ws://websocket.mtgox.com/mtgox
This is all I get.
hero member
Activity: 566
Merit: 500
Unselfish actions pay back better

Not sure, thing is that I can't connect to the mtgox websocket  Undecided

Mt. Gox' websockets are non-functional at the moment, could that be why?

This is an extremely simple websocket client that connects to Mt. Gox unless you give it another url:

Code:
#!/usr/bin/env python
# -*- mode: python; coding: utf-8 -*-

import sys
import os
import websocket

from sys import stdout, stderr
from datetime import datetime

MTGOX_WEBSOCKET_URI = 'ws://websocket.mtgox.com/mtgox'

GIMME_DEBUG = ('true', 't', 'yes', 'y', 'ja', 'j', '1')

def cb(ws, msg=None, fp=stdout):
    if msg is not None:
        log = '\t'.join([datetime.now().strftime('%F %T'), msg])
        fp.write(log)
        fp.write('\n')
        fp.flush()
    # end if
# end def cb

if os.environ.get('DEBUG', 'no').lower() in GIMME_DEBUG:
    websocket.enableTrace(True)
else:
    websocket.enableTrace(False)
# end if

if len(sys.argv) == 2:
    wsuri = sys.argv[1]
else:
    wsuri = MTGOX_WEBSOCKET_URI
# end if

ws = websocket.WebSocketApp(
    wsuri,
    on_open=lambda ws: cb(ws, 'opening %s' % wsuri, stderr),
    on_close=lambda ws: cb(ws, 'closing %s' % wsuri, stderr),
    on_message=cb,
    on_error=lambda ws, msg=None: cb(ws, msg, stderr)
)
rc = 0

try:
    ws.run_forever()
except (KeyboardInterrupt, SystemExit):
    rc = 0
except Exception:
    rc = 1
finally:
    try:
        ws.close()
    except:
        pass
    # end if
# end if

sys.exit(rc)
# eof

and all I get at the moment is this:

Code:
$ ./ws-test
2011-06-28 22:38:16 opening ws://websocket.mtgox.com/mtgox
2011-06-28 22:38:16 {"channel":"dbf1dee9-4f2e-4a08-8cb7-748919a71b21","op":"subscribe"}
2011-06-28 22:38:16 {"channel":"d5f06780-30a8-4a48-a2f8-7ed181b4a13f","op":"subscribe"}
2011-06-28 22:38:16 {"channel":"24e67e0d-1cad-4cc0-9e7a-f8523ef460fe","op":"subscribe"}
^C
2011-06-28 22:38:21 closing ws://websocket.mtgox.com/mtgox
$

Cheers,
member
Activity: 135
Merit: 10
Not sure, thing is that I can't connect to the mtgox websocket  Undecided
hero member
Activity: 566
Merit: 500
Unselfish actions pay back better

it uses the bitcoincharts telnet stream for time+sales instead of websockets because port 80 is blocked by my isp Sad

You mean that your ISP block ingoing traffic to port 80?  But only the outgoing traffic is to port 80, ingoing traffic cannot be to port 80 — at least not on Linux (unless you're root, which you shouldn't be in this case).

Cheers,
member
Activity: 135
Merit: 10
Screenshot:


This is a clone of MD TRADER in perl/tk.
I don't have any trading functionality implemented as of yet, because I don't have enough bitcoins to deposit to MtGox.
So if you want me to continue develop send me bitcoins until I reach 1 BTC on the address below. Or you could just implement it yourself, which should be easy if you know perl.

If you have windows you need activeperl first, and maybe install some packages through the package manager, but I'm not sure actually, I developed and tested it on windows ONLY but I don't know which packages aren't vanilla activeperl.

Please leave a comment.

Oh and it uses the bitcoincharts telnet stream for time+sales instead of websockets because port 80 is blocked by my isp Sad

Code:
use Tk;
use JSON;
use LWP::Simple;
use Net::Telnet;
use strict;
#use warnings;

#todo
#ticker
#multiple markets
#min volume / increment filter
#scrolling the ladder
#options
#actual trading lol


my $pid = fork();
if($pid){

my ($ask,$bid,$price,%bidx,%askx,$lastprice);
my $fixprice = 0;


    ##TK Shiznet
my($change,$volume,$ordersize,$defaultordersize,$togglecenter);

    my $mw = MainWindow->new;
    $mw->optionAdd('*font', 'Helvetica 10');
    $mw->title("BT Trader");
$mw->configure(-menu => my $menubar = $mw->Menu);


#menubar

my $filemb = $menubar->cascade(-label =>'File');
my $viewmb = $menubar->cascade(-label =>'View');

$filemb->command(
-label => 'Config',
-command => \&configure,
);

$filemb->command(
-label => 'Exit',
-command => sub {$mw->destroy();},
);

$viewmb->command(
-label => 'Time&Sales',
-command => \×ales,
);
$viewmb->command(
-label => 'Ticker',
-command => \&ticker,
);
    my $leftside = $mw->Frame;
$leftside->Checkbutton(-text => "Fixed", -variable=>\$togglecenter,-font => ['Helvetica', '8', 'bold'])->pack(-side =>'top');
    $leftside->pack(-side => 'left', -anchor => 'n');

#md ladder
    my $ladder = $mw->Frame(-borderwidth=>2, -relief => 'groove');
    for(my $i = 28; $i>0; $i--){
my($b,$p,$a);
        $ladder->Button(-width => 2)->grid(
        $b = $ladder->Button(-textvariable => \$bid->[$i], -background => 'DodgerBlue4', -foreground => 'white'),
        $p = $ladder->Button(-textvariable => \$price->[$i], -background => 'snow4', -foreground => 'white'),
        $a = $ladder->Button(-textvariable => \$ask->[$i], -background => 'red4', -foreground => 'white'),
        $ladder->Button(-textvariable => \$lastprice->[$i], -width => 4),
        -sticky => "nsew", -pady => 0
        );
        $b->configure(-command => [\&button_test, $b, $p ]);
        $p->configure(-command => [\&button_test, $p, $p ]);
        $a->configure(-command => [\&button_test, $a, $p ]);
        #$ladder->Canvas(-background=>red, height=>1)->grid("-","-","-","-",-pady => 0);
    }
    $ladder->pack(-side=>'left');
    $ladder->repeat(500, \&refresh);
    
  

    sub button_test{
        my ($var, $var2) = @_;
        
        $var = $var->cget(-textvariable);
        $var2= $var2->cget(-textvariable);
        print("$$var $$var2\n");
    }

#config window
my $cfg;
sub configure {

if (! Exists($cfg)) {
$cfg = $mw->Toplevel();
$cfg->title("Config");

}

else {
$cfg->deiconify( );
$cfg->raise( );
}

}

#time + sales
my ($tns,$tnsLB);
sub timesales{
if (! Exists($tns)) {
$tns = $mw->Toplevel();
$tns->title("Time&Sales");
$tnsLB = $tns->Listbox(-height => 30, -background => 'gray95', -relief => 'flat')->pack(-expand => 'y', -side=> 'left', -anchor => 'n');

}

else {
$tns->deiconify( );
$tns->raise( );
}
}

#ticker
my ($tkr,);
my @exchanges = ("MT Gox");
my (%thi, %tlo, %tla, %tby, %tsl, %tvol);
sub ticker{
if (! Exists($tkr)) {
$tkr = $mw->Toplevel();
$tkr->title("Ticker");
$tkr->Button(-text => "Exchange")->grid(
$tkr->Button(-text => "High"),
$tkr->Button(-text => "Low"),
$tkr->Button(-text => "Last"),
$tkr->Button(-text => "Bid"),
$tkr->Button(-text => "Ask"),
$tkr->Button(-text => "Volume"),
-sticky => "nsew");
foreach my $ex(@exchanges){
$tkr->Button(-text => "$ex")->grid(
$tkr->Button(-textvariable => \$thi{$ex}),
$tkr->Button(-textvariable => \$tlo{$ex}),
$tkr->Button(-textvariable => \$tla{$ex}),
$tkr->Button(-textvariable => \$tby{$ex}),
$tkr->Button(-textvariable => \$tsl{$ex}),
$tkr->Button(-textvariable => \$tvol{$ex}),
-sticky => "nsew");
}


}

else {
$tns->deiconify( );
$tns->raise( );
}
}

my $last;
    sub refresh{
        my($json,$json_txt,$json_ticker,$json_tl,$lastt);
    
        #market data
        open FILE, "md";
        $json = JSON->new->utf8;
        $json_txt = $json->decode( );
        close FILE;
        
        #ticker
        open FILE, "ticker";
        $json_ticker = $json->decode( );
        close FILE;
        $thi{"MT Gox"} = $json_ticker->{ticker}->{high};
        $tlo{"MT Gox"} = $json_ticker->{ticker}->{low};
        $tla{"MT Gox"} = $json_ticker->{ticker}->{last};
        $tby{"MT Gox"} = $json_ticker->{ticker}->{buy};
        $tsl{"MT Gox"} = $json_ticker->{ticker}->{sell};
        $tvol{"MT Gox"}= $json_ticker->{ticker}->{vol};
        
        #telnet feed
        open FILE, "telnet_mtg";
        
my($lasttime,$lastvol,@lst);
        #add time & sales
        while( ){

            $json_tl = $json->decode( $_ );
            if($lasttime != $json_tl->{timestamp} && Exists($tns) ){
print("$last $json_tl->{price}\n");
                $lasttime = $json_tl->{volume}."@".$json_tl->{price};
                $tnsLB->insert(0,$lasttime);
                if($last > $json_tl->{price}){
                    $tnsLB->itemconfigure(0, -foreground => "red");
                }
                if($last < $json_tl->{price}){
                    $tnsLB->itemconfigure(0, -foreground => "green4");
                }
$last = $json_tl->{price};
            }

$lasttime = $json_tl->{timestamp};
$last = $json_tl->{price};
$lastvol = $json_tl->{volume};
        }
        close FILE;

if(Exists($tns)){
unlink("telnet_mtg");
}
        
        
        #extract new data
        my @newprice;
        my %lp;
        
        #cleanup
        for (keys %askx){
            delete $askx{$_};
        }
        for (keys %bidx){
            delete $bidx{$_};
        }
        for (keys %lp){
            delete $lp{$_};
        }
        
        #extract data from dom json dump
        foreach my $item(@{$json_txt->{bids}}){
            $bidx{ @{$item}->[0] } = @{$item}->[1];
            push(@newprice,@{$item}->[0]);
          
        }
        foreach my $item(@{$json_txt->{asks}}){
            $askx{ @{$item}->[0] } = @{$item}->[1];
            push(@newprice,@{$item}->[0]);
            
        }
        @newprice = sort { $a <=> $b } @newprice;
        
        #last
        $lp{$last} = $lastvol;
        
        #fill the arrays
        my (@aska,@bida,@lpa);
my $x = 0;
        foreach my $item(@newprice){
            
            push(@bida,$bidx{$item}||"");
            push(@aska,$askx{$item}||"");
            push(@lpa,$lp{$item}||"");
        }
        
        
        #count offset + shift arrays
        my $i = 0;
        if($togglecenter || $fixprice == 0){
            while($askx{$newprice[$i]} eq ""){
                $i++;
            }
            $fixprice = $newprice[$i];
        }
        else{
            while($newprice[$i]<$fixprice){
                $i++;
            }
        }
        my $toshift = $i-15;
        for($i=0;$i<$toshift;$i++){
            shift(@newprice);
            shift(@aska);
            shift(@bida);
            shift(@lpa);
        }
        
        deep_copy(\@newprice,$price);
        deep_copy(\@aska,$ask);
        deep_copy(\@bida,$bid);
        deep_copy(\@lpa,$lastprice);
    }


sub deep_copy{
 my ($src,$tgt)=@_;
 if (ref $_[0] eq 'HASH'){copy_href(@_)}
 elsif (ref $_[0] eq 'ARRAY'){copy_aref(@_)}
}

sub copy_href{
 $_[1]||={};
 for my $key (keys %{$_[0]}){
if (ref $_[0]->{$key}){
 deep_copy($_[0]->{$key},$_[1]->{$key})
}
else {
 $_[1]->{$key} = $_[0]->{$key}
}
 }
}

sub copy_aref{
 $_[1]||=[];

 for my $i (0..$#{$_[0]}){
if (ref $_[0]->[$i]){
 deep_copy($_[0]->[$i],$_[1]->[$i])
}
else {
 $_[1]->[$i] = $_[0]->[$i]
}
 }
}
    
    MainLoop;
    kill 1, $pid;
    
}
else{
    
    $pid = fork;
    
    if($pid){
        while(1){
            getstore("https://mtgox.com/code/data/getDepth.php","md");
            getstore("https://mtgox.com/code/data/ticker.php","ticker");
            sleep 1;
        }
    }
    else{
    
        my $t = new Net::Telnet(Host=>"bitcoincharts.com", Port=>27007, Timeout=>999);
        my $line;
        
        while(1){
            $line = $t->getline();
            if($line =~ /mtgoxUSD/){
                open OUT, ">>telnet_mtg";
                print OUT "$line";
                close OUT;
            }
sleep 1;
        }
        
    }
}
Jump to: