From 364197b739d779a4b591a5595e29b87e142c0f65 Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Wed, 15 Jun 2011 20:36:39 +0200 Subject: [PATCH] autotrade-lohi.pl: First version, simple margin trader --- autotrade-lohi.pl | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100755 autotrade-lohi.pl diff --git a/autotrade-lohi.pl b/autotrade-lohi.pl new file mode 100755 index 0000000..a690a52 --- /dev/null +++ b/autotrade-lohi.pl @@ -0,0 +1,142 @@ +#!/usr/bin/perl +# +# Automated Bitcoin Trader - Low-High +# (c) Petr Baudis 2011 +# +# The automated trader maintains no persistent data except in MtGox +# order book. We still expect periodical user inspections; if you want +# to withdraw money, raise minbalance appropriately first and let enough +# outstanding transactions finish; alternatively, to withdraw k USD, +# in MtGox web interface place a buy order on k BTC @ 1 USD. +# +# Algorithm: +# +# We simply aim to generate profit by buying bitcoints and selling them +# at somewhat higher price to generate at least required margin. Each +# transaction is $bamount BTC and we seek to gain profit at least +# $sellmargin USD on it, therefore placing a sell order at $bamount*rate +# + fees + $sellmargin. +# +# Problems: +# 1. We buy coins immediately after selling them, incurring huge transaction +# costs. +# 2. We get blocked at local maximum, helpless when BTC start falling. +# +# Possible solutions: +# 1. Follow derivation over multiple timeframes. +# 2. Re-targetting old sell orders to avoid long-term blocks. +# 3. When price is dropping, sell part of investment if passing original +# value, so that we can re-invest in valley. +# +# +# TODO: +# We expire old buy orders. If it is older than $buyage minutes, throw +# it away, it is not going to happen. +# +# TODO: +# We also expire (re-target to current settings) old sell orders. +# We compute the expiration loss (we bought for X, now we are selling +# for less than X + margin), expected transaction loss (we expect to +# do $exptransperday successful transactions per day, how much we could +# make if the money was not sitting on idle sell order for all this time?) +# and when the ratio goes over $resellratio (say, 1) we accept the loss +# and sell the bitcoins to return them to circulation. +# +# Fee model: +# +# MtGox charges $tfee (0.0065) per transaction from the transaction value, +# i.e. the whole amount being charged. In a sell order (and re-targeting +# old sell orders!), we must top the target with fee compensation. E.g. for +# 20USD w/ 0.1USD profit margin, fees amount to 0.24USD!. + +# TODO: Better buy price selection based on market depth. +# TODO: Auto-adjust $sellmargin based on volatility? +# TODO: Auto-adjust $interval based on volatility? + +use warnings; +use strict; + + +# Configuration section. + +# First, trading parameters. + +my $bamount = 0.618; # [BTC] transaction size +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!). +my $minbalance = 10; # [USD] minimum balance to keep on account + + +# Then, information about our trader. + +my $interval = 20; # [s] trade cycle period +my $tfee = 0.0065; # [ratio] transaction fee - multiply by transaction amount + +our @mgrc = split /\n/, `cat ~/.mgrc`; +use WebService::MtGox; +my $t = WebService::MtGox->new(user => $mgrc[0], password => $mgrc[1]); + + +# Configuration end. + + +sub currency { + sprintf '%.3f', $_[0]; +} + +sub tfee_compensation { + my ($buy, $sell) = @_; + # This solves the equation + # (buy + (sell + fees)) * tfee = fees + # returning $fees - the amount we need to charge extra for + # bitcoints to compensate for transaction fees. + return ($buy + $sell) * $tfee / (1 - $tfee); +} + +my $last_balance; + +sub should_trade { + my $binfo = $t->list(); + my $balance = $binfo->{usds}; + print "\t\tBasic balance $balance\n"; + foreach my $o (@{$binfo->{orders}}) { + if ($o->{type} == '2') { + print "\t\t- Buy order $o->{amount} @ $o->{price}\n"; + $balance -= $o->{amount} * $o->{price}; + } + } + print "\tEffective balance $balance\n"; + $last_balance = $balance - $minbalance; + return $balance > $minbalance; +} + +sub do_trade { + my $tinfo = $t->get_ticker()->{ticker}; + my $brate = $tinfo->{sell}; + my $srate = $brate + $sellmargin; + my $fees = currency(tfee_compensation($brate, $srate)); + $srate += $fees; + print "\t\tCurrent buy rate $tinfo->{buy}, our buy rate $brate, fees $fees, sell rate $srate\n"; + + my $uamount = currency($brate * $bamount); + my $uamount2 = currency($srate * $bamount); + print "\t\tWould buy $bamount BTC for $uamount USD (balance $last_balance USD), will sell for $uamount2 USD\n"; + if ($last_balance <= $uamount) { + print "\tNot enough funds.\n"; + return 0; + } + + $t->buy(amount => $bamount, price => $brate); + $t->sell(amount => $bamount, price => $srate); + print "\t* Orders PLACED. *\n"; + return 1; +} + + +while (1) { + print "... ".localtime." check\n"; + while (should_trade() and do_trade()) { + sleep 1; + } + print "... ".localtime." check finished.\n\n"; + sleep $interval; +} -- 2.11.4.GIT