minzie (OP)
|
|
April 24, 2013, 12:13:01 AM Last edit: April 24, 2013, 10:28:45 PM by minzie |
|
I have been toying around with a trading bot for a little bit now, mostly as an exercise in creating a simple trading bot that is easily usable. I also wanted to start with something that was easily approachable for novice programmers, so I tried to keep everything clear and clean. It is simply one big loop that runs until the program is manually terminated. There is absolutely no trading functionality in it at all, although from the API, it looks pretty easy to implement. Regardless of one's opinion, PHP is a perfectly acceptable language that is accessible for many people. It is always fun to put code out in public, so yeah.... this is just a proof of concept for people that may be less experienced with software development; a platform with which to start tinkering. Or maybe ask questions. Or maybe contribute some code. I'ma just gonna paste the entire thing in here and see what happens: <?php /* * By: cclites@minzie.com 2013-04-22 * For: Minzie.com * Version: .01 * BTC Donations: 19aTxxfEm6JSRHnW9yektMbwfyxaySWfKv * * * Implements the Bitstamp api. * https://www.bitstamp.net/api/ */ writeLog("."); writeLog("**************************************"); writeLog("**************************************"); writeLog("bot is starting up"); writeLog("**************************************"); writeLog("**************************************"); $usd = 0; //Amount in account of user in US dollars $btc = 0.03; //Amount of Bitcoin in User account $lastClose = array(); //Array of closing prices, with the last being the most current. $direction = 0; //Current trend // - incremented if increasing // - decremented if decreasing $maxIncrease = .05; //Percent increase from last sale $maxDecrease = .05; //Percent decrease from last sale $tradingFee = .05; //Percent of trading fee $lastPurchase = array(); //Array of prices of purchases, with the last being the most current. $lastSale = array(); //Array of prices of sales, with the last being the most current. $failSafe = 0; //This is the BTC floor. Sell nothing past this amount, whatever it may be. $base = 123.97; //Base price in USD for calculating buy/sell points. $drop = 5; //US dollar decrease since last sale. $increase = 10; //US dollar increase since last sale. $direction = 0; //Direction of last from previous last $trend = 0; //Number of price-points in current trend $xchangeFee = .004; //Bitstamp exchange fee .4% $buyFlag = true; //Flag indicating permission to buy $sellFlag = true; //Flag indicating permission to sell /*For transaction testing*/ $index = 0; $testUsd = 100.00; $testBtc = 1; $testPricePoints = array(100, 105, 100); $usd = $testUsd; $btc = $testBtc; /******************************************* * ROUTINE ********************************************/ updateState();
function updateState() { global $lastClose, $lastPurchase, $lastSale, $direction, $usd, $btc, $base, $drop, $increase, $trend, $direction, $xchangeFee; $ticker = null; /*** Retrieve ticker to get the last close price. ***/ getTicker($ticker); /****************************************************/ /*** Once we get the ticker, we need to update lastClose ***/ updateLastClose($ticker); $last = (float)end($lastClose); $previousLast = (float)prev($lastClose); /*** Update trend information ****/ if($last < $previousLast) { if ($direction == 1) $trend = 0; else $trend += 1; $direction = -1; } else if ($last > $previousLast) { if ($direction == -1) $trend = 0; else $trend += 1; $direction = 1; } else { $trend = 0; $direction = 0; } /**********************************/ /*** Initialize base if seeing this for the first time ***/ if($base == -1) $base = $last; $totalFee = (1 + $xchangeFee); $salePoint = (($base * $totalFee) + $increase); $purchasePoint = (($base - ($base * $xchangeFee)) - $drop); writeLog("($base * $totalFee) + $increase"); writeLog("($base - ($base * $xchangeFee)) - $drop"); writeLog("SPP: " . $purchasePoint . " PPP: " . $salePoint); // 'direction' is used to make sure not to trigger a sell // if the price is still rising (trend), or to trigger // a buy if the price is still falling. if ($last > $salePoint && $direction == -1 && $btc > 0 ) { $direction += 1; writeLog("SELLING at " . $last . " per Bitcoin. "); $lastSale[] = $last; $base = $last; $usd += ($btc * $last); $btc = 0; } else if ($last < $purchasePoint && $direction == 1 && $usd > 0) { $direction -= 1; writeLog("BUYING at " . $last . " per Bitcoin. "); $lastPurchase[] = $last; $base = $last; $btc += ( (float)$usd/(float)$last); $usd = 0; } writeLog("LAST: " . $last . " PREVIOUS LAST: " . $previousLast); writeLog("WALLET: USD: " . $usd . " BTC: " . $btc); writeLog("DIRECTION: " . $direction . " TREND: " . $trend); writeLog("."); sleep(30); // Debugging /* global $index, $testPricePoints; if ($index == count($testPricePoints) ) { writeLog("<pre>"); print_r($lastClose); writeLog("</pre><br>"); exit; } */ updateState(); } /* * Just saves the last price to the lastClose array */ function updateLastClose(&$ticker) { global $lastClose, $lastPurchase, $lastSale;
if(end($lastClose) != $ticker->last) { $lastClose[] = $ticker->last; }
// Initialize arrays if seeing this for the first time. if (count($lastClose) == 1) { $lastClose[] = $ticker->last; $lastPurchase[] = $ticker->last; $lastSale[] = $ticker->last; } } /* * Returns the Bitstamp ticker object * * stdClass Object * ( * [high] => 121.00 * [last] => 119.96 * [bid] => 119.96 * [volume] => 8291.58742485 * [low] => 106.00 * [ask] => 120.98 * ) * * Parameters: * $ticker - represents the ticker object */ function getTicker(&$ticker) { global $lastClose, $lastPurchase, $lastSale; $url = "https://www.bitstamp.net/api/ticker/"; curl($url, $ticker); } /* * Used to simulate a 3 point update with known values to do allow * some crude testing. * * Parameters: * $ticker - represents the ticker object */ function getTestTicker(&$ticker) { global $testPricePoints, $index, $lastClose, $lastPurchase, $lastSale; writeLog("index is $index<br>"); $ticker->last = $testPricePoints[$index]; writeLog("<pre>"); print_r($ticker); writeLog("</pre><br>"); $index += 1; } /* * Just a wrapper to allow reuse of the curl functionality. * * Parameters: * $result - represents the ticker object * $url - represents the REST request */ function curl($url, &$result) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $result = json_decode(curl_exec($ch)); curl_close($ch); return 0; } function writeLog($message) { $address = 'bot.log'; $timeStamp = date ("D M d H:i:s Y"); $f = fopen($address, "a"); if ($message == "") { fwrite( $f, " "); } else { fwrite( $f, $timeStamp . ": $message\n\r" ); } fclose( $f ); return 0; } ?>
Sorry, cut and paste munged the formatting a bit. And sorry to the first person that tries to use this and finds that it doesn't work. I only changed one thing before I posted this. I'm sure it was fine.
|
|
|
|
minzie (OP)
|
|
April 24, 2013, 12:53:10 AM |
|
Cool. Maybe you should share some of your code......
|
|
|
|
paraipan
In memoriam
Legendary
Offline
Activity: 924
Merit: 1004
Firstbits: 1pirata
|
|
April 24, 2013, 01:05:51 AM |
|
Cool. Maybe you should share some of your code......
+1
|
BTCitcoin: An Idea Worth Saving - Q&A with bitcoins on rugatu.com - Check my rep
|
|
|
gweedo
Legendary
Offline
Activity: 1498
Merit: 1000
|
|
April 24, 2013, 01:30:41 AM |
|
Cool. Maybe you should share some of your code......
+1 Yeah months and months of testing and time should just be handed out, so other people get rich. LMAO not happening, but I will make you a deal, get a bounty of about 80BTC and I will release as a framework so people can build off of it and add there own trading logic.
|
|
|
|
paraipan
In memoriam
Legendary
Offline
Activity: 924
Merit: 1004
Firstbits: 1pirata
|
|
April 24, 2013, 01:58:59 AM |
|
Cool. Maybe you should share some of your code......
+1 Yeah months and months of testing and time should just be handed out, so other people get rich. LMAO not happening, but I will make you a deal, get a bounty of about 80BTC and I will release as a framework so people can build off of it and add there own trading logic. Sharing it's a good thing...
|
BTCitcoin: An Idea Worth Saving - Q&A with bitcoins on rugatu.com - Check my rep
|
|
|
minzie (OP)
|
|
April 24, 2013, 02:25:06 AM |
|
Oh. I misunderstood. I thought it starkly obvious to anyone that knows anything about code that this isn't suitable for production. But, you know, big shocker getting a critique from someone trying to drum up business as a developer.
A monkey can write a bot to make money on bitcoin right now.
Funniest shit I've seen all day.
|
|
|
|
gweedo
Legendary
Offline
Activity: 1498
Merit: 1000
|
|
April 24, 2013, 02:33:15 AM |
|
Cool. Maybe you should share some of your code......
+1 Yeah months and months of testing and time should just be handed out, so other people get rich. LMAO not happening, but I will make you a deal, get a bounty of about 80BTC and I will release as a framework so people can build off of it and add there own trading logic. Sharing it's a good thing... LMAO not when it could make someone else a boat load of money. Oh. I misunderstood. I thought it starkly obvious to anyone that knows anything about code that this isn't suitable for production. But, you know, big shocker getting a critique from someone trying to drum up business as a developer.
A monkey can write a bot to make money on bitcoin right now.
Funniest shit I've seen all day.
You do know some newbie will try it anyway, I just wanted to protect them. Also you just asked me to release my bot, I didn't even bring up that I have a trading bot until you said I should release mine. So your drumming up business for me. Also a monkey can't write a bitcoin trading bot, that can trade on it's own. Yes a monkey can make it so it buys at certains prices and sells at certains prices/percentages.
|
|
|
|
minzie (OP)
|
|
April 29, 2013, 11:02:30 PM |
|
I broke this out into a few classes that make a little more sense, and actually provides some structure. I suppose technically at this point this is only a Bitcoin trading simulation with lofty aspirations. <?php /* * By: cclites@minzie.com 2013-04-28 * For: Minzie.com * Version: .1 Controller.php * BTC Address: 19aTxxfEm6JSRHnW9yektMbwfyxaySWfKv * * * Implements the Bitstamp api. * https://www.bitstamp.net/api/ */
/* * Controller.php - Main entry point for this testing/development framework. * (hint: run this class); * * This is a simple procedural class with a recursive function call to update * every 30 seconds. Its job is to create a single LazyI instance, process * market info, and notify the bot when the information has been updated. * * This is being tested on a LAMP stack, running from the command line. * */
require_once("Configs.php"); require_once("Utilities.php"); require_once("Lazy_I.php"); /* * These fields will eventually live in a database. They are used to represent * the market state. */ $lastClose = -1; $direction = 0; $trend = 0; $ticker; $high = 0; $low = 0; $botArray = array(); writeLog("************* LazyI Starting up. *******************"); init($ticker); writeLog("PREVIOUS LAST CLOSE: " . $lastClose); writeLog("CURRENT LAST: " . number_format($ticker->last, 8)); $last = number_format((float)$ticker->last,8); updateTrend($last, $lastClose, $direction, $trend); writeLog("DIRECTION: " . $direction . " TREND: " . $trend); writeLog("INSTANTIATE LazyI."); /* * NOTE: This Lazy_I class constructor will be expanded to pass other initialization * attributes, pulled from $_POST. For now, use these defaults */ $basePoint = 150; $startUsd = 20; $startBtc = .2; $bot = new Lazy_I($basePoint, $startUsd, $startBtc); $bot->checkTransactionRules($ticker->last, $direction, $trend); $botArray[] = $bot; mainRoutine($ticker);
/* * function: update * * This function retrieves and updates market information, and then * processes the bots. */ function update() { global $botArray, $lastClose, $usd, $btc, $direction, $trend; getTicker($ticker); writeLog("PREVIOUS LAST CLOSE: " . $lastClose); writeLog("CURRENT LAST: " . number_format($ticker->last, 8)); $last = number_format((float)$ticker->last,8); updateTrend($last, $lastClose, $direction, $trend); writeLog("DIRECTION: " . $direction . " TREND: " . $trend); $cnt = count($botArray); for ($i = 0; $i < $cnt; $i += 1) { $tmpBot = $botArray[$i]; $tmpBot->update(); $tmpBot->checkTransactionRules($ticker->last, $direction, $trend); } mainRoutine($ticker); } function mainRoutine(&$ticker) { updateLastClose($ticker); sleep(30); update(); } ?>
<?php /* * By: cclites@minzie.com 2013-04-28 * For: Minzie.com * Version: .1 Configs.php * BTC Address: 19aTxxfEm6JSRHnW9yektMbwfyxaySWfKv * * * Implements the Bitstamp api. * https://www.bitstamp.net/api/ */
define("LOG", "lazyI_v1_dev.log"); define("GET_TICKER", "https://www.bitstamp.net/api/ticker/"); define("GET_BALANCE", "https://www.bitstamp.net/api/balance/"); define("USER", "********"); define("PASSWORD","********"); ?>
<?php /* * By: cclites@minzie.com 2013-04-28 * For: Minzie.com * Version: .1 Utilities.php * BTC Address: 19aTxxfEm6JSRHnW9yektMbwfyxaySWfKv * * * Implements the Bitstamp api. * https://www.bitstamp.net/api/ */ /* * Utilities.php - main library for common functions. * * Realistically, this should be divided into market-related utilities * and bot-related utilities. The set of functions is small enough for * now that I can live with it. */ /* * Set the exchange state */ function init(&$ticker) { getTicker($ticker); } /* * Returns the Bitstamp ticker object * * Example ticker content: * * stdClass Object * ( * [high] => 121.00 * [last] => 119.96 * [bid] => 119.96 * [volume] => 8291.58742485 * [low] => 106.00 * [ask] => 120.98 * ) * * Parameters: * $ticker - represents the ticker object */ function getTicker(&$ticker) { $url = GET_TICKER; writeLog("Getting TICKER: $url"); curl($url, $ticker); if(!$ticker) { writeLog("Error retrieving ticker."); return 0; } return 1; } function writeLog($message) { $address = LOG; $timeStamp = date ("D M d H:i:s Y"); $f = fopen($address, "a"); if($message == "") { fwrite($f, "\n"); } else { fwrite( $f, $timeStamp . ": $message\n\r" ); //echo("$timeStamp: $message\n\r<br>"); } fclose($f); return 0; } /* * Wrapper to allow reuse of the curl functionality for GET requests. * * Parameters: * $result - represents the ticker object * $url - represents the REST request */ function curl($url, &$result) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $result = json_decode(curl_exec($ch)); curl_close($ch); return 1; } /* * Wrapper to allow reuse of the curl functionality for POST requests. * * Parameters: * $result - represents the ticker object * $str - * $url - represents the REST request */ function pCurl($url, $str, &$result) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt ($ch, CURLOPT_POST, 1); curl_setopt ($ch, CURLOPT_POSTFIELDS, $str); $result = json_decode(curl_exec($ch)); curl_close($ch); return 1; } /* * Update the market trend and direction * * Parameters: * $last - represents latest market close in USD * $lastClose - represents previous market close in USD * * Returns: * $direction - represents market direction as an int. * $trend - represents trend as an int. */ function updateTrend($last, $lastClose, &$direction, &$trend) { if($last < $lastClose) { if( $direction == -1) //was already decreasing { $trend += 1; } else { $trend = 1; $direction = -1; } } else if ($last > $lastClose) { if( $direction == 1) //was already increasing { $trend += 1; } else { $trend = 1; $direction = 1; } } else { $trend = 0; $direction = 0; } return 1; } /* * Gets balance information for a user. Currently, testing only supports a single account. * */ function getBalanceInformation(&$balance) { global $usd, $btc, $xchangeFee, $user, $password; $url = GET_BALANCE; $str = "user=" . USER . "&password=" . PASSWORD; $account; pCurl($url, $str, $balance); } /* * Just saves the last price to the lastClose array */ function updateLastClose($ticker) { global $lastClose, $high, $low; if(!$ticker) return; // if ticker is empty, wait until next go-round. if( $ticker->last > $high) { $high = $lastClose; } else if ($ticker->last < $low) { $low = $lastClose; } // Initialize arrays if seeing this for the first time. if ($lastClose == -1) { $lastClose = number_format($ticker->last, 8); $high = $low = $lastClose; }
if( $lastClose != $ticker->last) { $lastClose = number_format($ticker->last, 8); } writeLog("********************LAST CLOSE IS $lastClose"); writeLog("HIGH $high LOW $low"); } ?>
<?php /* * By: cclites@minzie.com 2013-04-28 * For: Minzie.com * Version: .1 Lazy_I.php * BTC Address: 19aTxxfEm6JSRHnW9yektMbwfyxaySWfKv * * * Implements the Bitstamp api. * https://www.bitstamp.net/api/ */
require_once("Utilities.php"); require_once("Transaction.php"); class Lazy_I { /* * These fields will eventually be moved onto a database. */ var $spp = 0; var $ppp = 0; var $base = -1; var $usd = 0; var $btc = 0; var $exchangeFee = 0; var $increase = 5; var $decrease = 5; public function Lazy_I($basePoint, $_usd, $_btc) { writeLog("Initializing bot instance"); writeLog("Base point is $basePoint"); $this->base = $basePoint; $this->usd = $_usd; $this->btc = $_btc; $this->update(); return 1; } public function update() { writeLog("Updating"); $this->getBalance(); $this->calculatePricePoints(); } public function getBalance() { writeLog("Getting Balance"); getBalanceInformation($balance); /* * For testing, we want to use the values provided in the initialization * of the object. Uncomment for account-based testing. */ //$this->usd = $balance->usd_available; //$this->btc = $balance->btc_available; $this->exchangeFee = ($balance->fee) / 100; writeLog("WALLET: USD: " . $this->usd . " BTC: " . $this->btc); return 1; } /* * Kick off the price point calculations */ public function calculatePricePoints() { $totalFee = (1 + ($this->exchangeFee)); $this->calculateSellPoint($totalFee); $this->calculateBuyPoint(); writeLog("SPP: " . $this->spp . " PPP: " . $this->ppp); return 1; } /* * Calculate sell point. This is used to determine the point at which * a sell order would be placed. */ public function calculateSellPoint($totalFee) { writeLog("Calculating sell point."); $this->spp = (($this->base * $totalFee) + $this->increase); return 1; } /* * Calculate buy point. This is used to determine the point at which * a buy order would be placed. */ public function calculateBuyPoint() { writeLog("Calculating buy point."); $this->ppp = (($this->base - ($this->base * $this->exchangeFee)) - $this->decrease); return 1; } /* * Process business transaction rules. */ public function checkTransactionRules($lastClose, $direction, $trend) { writeLog("CHECKING TRANSACTIONS"); $this->checkSell($lastClose, $direction, $trend); $this->checkBuy($lastClose, $direction, $trend); return 1; } /* * Determine if the sell point conditions */ public function checkSell($lastClose, $direction, $trend) { //writeLog("CHECK SELL $lastClose : $direction : $trend"); //writeLog("SPP " . $this->spp . " BTC " . $this->btc); //return; writeLog("$lastClose > " . $this->spp . " && $direction == -1 && " . $this->btc ."> 0 "); if ($lastClose > $this->spp && $direction == -1 && $this->btc > 0 ) { writeLog("SELLING at " . $lastClose . " per Bitcoin. "); // STUB: create sell transaction createSellTransaction(); $this->base = $lastClose; //This goes away in production because the account info will be updated when //the bots are updated. This will be updated on the bitstamp side. $this->usd += ($this->btc * $last); $this->btc = 0; } return 1; } public function checkBuy($lastClose, $direction, $trend) { //writeLog("CHECK BUY $lastClose : $direction : $trend"); //writeLog("PPP " . $this->ppp . " USD " . $this->usd); //return; writeLog("$lastClose < " . $this->ppp . " && $direction == 1 && " . $this->usd ."> 0 "); if ($lastClose < $this->ppp && $direction == 1 && $this->usd > 0 ) { writeLog("BUYING at " . $lastClose . " per Bitcoin. "); // STUB: create buy transaction createBuyTransaction(); $this->base = $lastClose; //This goes away in production because the account info will be updated when //the bots are updated. This will be updated on the bitstamp side. $this->btc += number_format(((float)$this->usd/(float)$lastClose),8); $this->usd = 0; } return 1; } public function getLazyI() { return $this; } }
?>
<?php /* * By: cclites@minzie.com 2013-04-28 * For: Minzie.com * Version: .1 Transaction.php * BTC Address: 19aTxxfEm6JSRHnW9yektMbwfyxaySWfKv * * * Implements the Bitstamp api. * https://www.bitstamp.net/api/ */ require_once("Configs.php"); require_once("Utilities.php"); function createBuyTransaction() { writeLog("STUB: createBuyTransaction"); } function createSellTransaction() { writeLog("STUB: createSellTransaction"); } ?>
|
|
|
|
Malawi
Full Member
Offline
Activity: 224
Merit: 100
One bitcoin to rule them all!
|
|
April 29, 2013, 11:46:33 PM |
|
You should use java, so you can better abstract the exchange, so you can easily add more power trading logic , using php for a trading bot is the worst idea ever. If you run this long enough you going to have some issues I can spot them already. Only thing you did right was set it for bitstamp. I have forgotten most of my coding capabillities, but to me it seems like Java has too many holes and exploit to handle valuables.
|
BitCoin is NOT a pyramid - it's a pagoda.
|
|
|
ASICPool
Member
Offline
Activity: 80
Merit: 10
|
|
April 30, 2013, 12:06:17 AM |
|
You should use java, so you can better abstract the exchange, so you can easily add more power trading logic , using php for a trading bot is the worst idea ever. If you run this long enough you going to have some issues I can spot them already. Only thing you did right was set it for bitstamp. I have forgotten most of my coding capabillities, but to me it seems like Java has too many holes and exploit to handle valuables. It's not like the Java would be run on a public server, so I don't know what you mean by exploited.
|
|
|
|
minzie (OP)
|
|
April 30, 2013, 12:27:25 AM |
|
The right language is the one that is right for the implementation. It seems, to me, snobbish to criticize a language or implementation without first asking about how the code will be used. It is hilarious, to me, that anyone claiming any level of trade skills would not at least ask those obvious questions first. YMMV.
@Malavi, there is actually a good java library pointed it out in another bot trading thread somewhere, and not a chance in hell I could ever find it again. This is a project in my spare time, and PHP is easy. It is also accessible to more people, so I can easily share.
|
|
|
|
|