autotrade-lohi.pl: First version, simple margin trader
[autotrade.git] / autotrade-lohi.pl
bloba690a520f93832bddb069b9643a030b733a9691d
1 #!/usr/bin/perl
3 # Automated Bitcoin Trader - Low-High
4 # (c) Petr Baudis <pasky@ucw.cz> 2011
6 # The automated trader maintains no persistent data except in MtGox
7 # order book. We still expect periodical user inspections; if you want
8 # to withdraw money, raise minbalance appropriately first and let enough
9 # outstanding transactions finish; alternatively, to withdraw k USD,
10 # in MtGox web interface place a buy order on k BTC @ 1 USD.
12 # Algorithm:
14 # We simply aim to generate profit by buying bitcoints and selling them
15 # at somewhat higher price to generate at least required margin. Each
16 # transaction is $bamount BTC and we seek to gain profit at least
17 # $sellmargin USD on it, therefore placing a sell order at $bamount*rate
18 # + fees + $sellmargin.
20 # Problems:
21 # 1. We buy coins immediately after selling them, incurring huge transaction
22 # costs.
23 # 2. We get blocked at local maximum, helpless when BTC start falling.
25 # Possible solutions:
26 # 1. Follow derivation over multiple timeframes.
27 # 2. Re-targetting old sell orders to avoid long-term blocks.
28 # 3. When price is dropping, sell part of investment if passing original
29 # value, so that we can re-invest in valley.
32 # TODO:
33 # We expire old buy orders. If it is older than $buyage minutes, throw
34 # it away, it is not going to happen.
36 # TODO:
37 # We also expire (re-target to current settings) old sell orders.
38 # We compute the expiration loss (we bought for X, now we are selling
39 # for less than X + margin), expected transaction loss (we expect to
40 # do $exptransperday successful transactions per day, how much we could
41 # make if the money was not sitting on idle sell order for all this time?)
42 # and when the ratio goes over $resellratio (say, 1) we accept the loss
43 # and sell the bitcoins to return them to circulation.
45 # Fee model:
47 # MtGox charges $tfee (0.0065) per transaction from the transaction value,
48 # i.e. the whole amount being charged. In a sell order (and re-targeting
49 # old sell orders!), we must top the target with fee compensation. E.g. for
50 # 20USD w/ 0.1USD profit margin, fees amount to 0.24USD!.
52 # TODO: Better buy price selection based on market depth.
53 # TODO: Auto-adjust $sellmargin based on volatility?
54 # TODO: Auto-adjust $interval based on volatility?
56 use warnings;
57 use strict;
60 # Configuration section.
62 # First, trading parameters.
64 my $bamount = 0.618; # [BTC] transaction size
65 my $sellmargin = 0.1; # [USD] sell order above current rate plus this margin; this * bamount is how much we make per transaction (up to fees!).
66 my $minbalance = 10; # [USD] minimum balance to keep on account
69 # Then, information about our trader.
71 my $interval = 20; # [s] trade cycle period
72 my $tfee = 0.0065; # [ratio] transaction fee - multiply by transaction amount
74 our @mgrc = split /\n/, `cat ~/.mgrc`;
75 use WebService::MtGox;
76 my $t = WebService::MtGox->new(user => $mgrc[0], password => $mgrc[1]);
79 # Configuration end.
82 sub currency {
83 sprintf '%.3f', $_[0];
86 sub tfee_compensation {
87 my ($buy, $sell) = @_;
88 # This solves the equation
89 # (buy + (sell + fees)) * tfee = fees
90 # returning $fees - the amount we need to charge extra for
91 # bitcoints to compensate for transaction fees.
92 return ($buy + $sell) * $tfee / (1 - $tfee);
95 my $last_balance;
97 sub should_trade {
98 my $binfo = $t->list();
99 my $balance = $binfo->{usds};
100 print "\t\tBasic balance $balance\n";
101 foreach my $o (@{$binfo->{orders}}) {
102 if ($o->{type} == '2') {
103 print "\t\t- Buy order $o->{amount} @ $o->{price}\n";
104 $balance -= $o->{amount} * $o->{price};
107 print "\tEffective balance $balance\n";
108 $last_balance = $balance - $minbalance;
109 return $balance > $minbalance;
112 sub do_trade {
113 my $tinfo = $t->get_ticker()->{ticker};
114 my $brate = $tinfo->{sell};
115 my $srate = $brate + $sellmargin;
116 my $fees = currency(tfee_compensation($brate, $srate));
117 $srate += $fees;
118 print "\t\tCurrent buy rate $tinfo->{buy}, our buy rate $brate, fees $fees, sell rate $srate\n";
120 my $uamount = currency($brate * $bamount);
121 my $uamount2 = currency($srate * $bamount);
122 print "\t\tWould buy $bamount BTC for $uamount USD (balance $last_balance USD), will sell for $uamount2 USD\n";
123 if ($last_balance <= $uamount) {
124 print "\tNot enough funds.\n";
125 return 0;
128 $t->buy(amount => $bamount, price => $brate);
129 $t->sell(amount => $bamount, price => $srate);
130 print "\t* Orders PLACED. *\n";
131 return 1;
135 while (1) {
136 print "... ".localtime." check\n";
137 while (should_trade() and do_trade()) {
138 sleep 1;
140 print "... ".localtime." check finished.\n\n";
141 sleep $interval;