Archiv štítku: programování

Jak například využít API COINBASE PRO

Co je to vlastně to API?
Jednoduše řečeno jedná se o způsob jakým vykonávat (v případě Coinbase) operace nad portfoliem vzdáleně z prostředí své aplikace, případně svého scriptu.

Co konkrétně můžu dělat?
Vše co se dá dělat je zdokumentováno, ale abych vás čtenáře takto neodbyl, tak příkladem jsou metody (funkce) pro získání přehledů produktů, za kolik se aktuálně obchodují, data k vykreslení candle grafů, správa objednávek a mnoho dalších.

Co konkrétně používám?
Na API jsem se napojil, abych si v budoucnu mohl vytvořit (naprogramovat) svoji investiční strategii a tu automatizovat. Protože, jak jsem dříve psal, je třeba sledovat výkyvy ceny, ty analyzovat a na základě toho nakupovat a prodávat. A když to nějak svedu já, tak v případě dostatku dat a možnosti algoritmizace, může počítač vyhodnocovat situaci například co pět sekund včetně noci a ne jako já jen několikrát denně. Ale aktuálně je to velké sousto, protože jsem se nad tím zamyslel a uvědomil si s čím vším podvědomě pracuji a jak na to nahlížím. A to co se dá nazvat intuicí by bylo potřeba nahradit velkým množstvím matematiky, kterou bych si musel osvěžit, případně nastudovat (o tom snad jindy :-))…
Takže jsem si aktuálně zvolil menší konkrétní cíl, který mi ale usnadní usnadnit jeden konkrétní případ užití (anglicky „Use case“, takže budu používat jen zkratku UC)…

Můj případ užití
Pokud vidíte v grafu několik opakujících se vlnek, které mají maximum někde kolem 1,3 EUR (pro kryptoměnu Ox (ZRX)) a minimum klesá někde k hodnotě 1,2 EUR, tak je fajn si nastavit nákup v režimu LIMIT a nemuset to stále sledovat. Můj návyk je, že si určuji, jaký chci mít náklad na jeden obchod, abych diverzifikoval riziko a následně si určím jaký chci mít výnos při prodeji. Takže například chci nakoupit přesně za 500 EUR a následně nastavit prodej na 510 EUR, zde již po odečtení FEE, takže čistý výnos 10 EUR. O tom jsem více psal v dříve publikovaném článku. Problém je ten, že v režimu LIMIT se takto naplánovat transakce nedá. Jako vstupní pole jsou „jednotková cena za kryptoměnu“ a „počet jednotek, které chci koupit“. No a nyní se dostávám k té pointě, že si tento jednoduchý formulář mohu přetvořit k obrazu svému a na pozadí si dopočítat počet kupovaných jednotek tak, abych se dostal na těch kýžených 500 EUR.

Objednávkový formulkář v režimu LIMIT
Objednávkový formulář v režimu LIMIT – zadána cena 1,2 EUR/ks a počet 400 ks, ale cena je 481,68 EUR. A takto bych musel iterovat nebo na kalkulačce počítat tak dlouho, dokud bych se nedostal na 500 EUR.

Můj formulář je ale přesně takový, jaký vyhovuje mému UC.
Vlastní formulář
Vlastní formulář, kde zadám přesně co chci a na pozadí se mi provede výpočet a založí daná objednávka.

Co je na pozadí?
Základem je jednoduchá třída pro komunikaci s Coinbase API:

<?php
 
class CoinbaseExchange {
	protected $key;
	protected $secret;
	protected $passphrase;
 
	protected $endpoint = 'https://api.pro.coinbase.com';
	protected $timestamp;
 
	public function __construct($key, $secret, $passphrase) {
		$this->key = $key;
		$this->secret = $secret;
		$this->passphrase = $passphrase;
		$this->timestamp = time();
	}
 
	private function signature($request='', $body='', $method='GET') {
		$body = is_array($body) ? json_encode($body) : $body;
		$what = $this->timestamp.$method.$request.$body;
 
		return base64_encode(hash_hmac("sha256", $what, base64_decode($this->secret), true));
	}
 
	public function sendRequest($request, $body='', $method='GET', $auth=false) {
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $this->endpoint.$request);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		if (strcasecmp($method, 'POST') === 0) {
			curl_setopt($ch, CURLOPT_POST, 1);
			curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
		}
		curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
 
		if ($auth) {
			$headers = array();
			$headers[] = "Content-Type: application/json";
			$headers[] = "CB-ACCESS-KEY: " . $this->key;
			$headers[] = "CB-ACCESS-SIGN: " . $this->signature($request, $body, $method);
			$headers[] = "CB-ACCESS-TIMESTAMP: " . $this->timestamp;
			$headers[] = "CB-ACCESS-PASSPHRASE: " . $this->passphrase;
			curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
		}
 
		$output = curl_exec($ch);
 
		if(curl_getinfo($ch, CURLINFO_HTTP_CODE) !== 200) {
			return $output;
		}
 
		curl_close($ch);
		return $output;
	}
}
?>

A pak implementace volání konkrétního requestu, dle dokumentace:

$cb = new CoinbaseExchange(KEY, SECRET, PASSPHRASE); // získáte při registraci
 
$totalPrice = (int)$_POST['totalPrice'];
$fee = 0.0035;
$price = (double)$_POST['price'];
$size = round(($totalPrice - ($totalPrice * $fee)) / $price, 2);
 
$request = '/orders';
$body = array(
    "size" => "$size",
    "price" => "$price",
    "side" => "buy",
    "product_id" => "ZRX-EUR"
);
 
$response = $cb->sendRequest($request, $body, 'POST', true);
 
echo $response; // json message, dá se dále zpracovat

Záměrně jsem kód hodně zjednodušil, aby z něho bylo patrné to podstatné. Například $fee, se dá také načítat aktuálně pomocí API, ale další řádky by zápis jen učinily nepřehledným.

Ta kouzelná formule, kterou „aplikace“ dělá za mě je tento řádek,

$size = round(($totalPrice - ($totalPrice * $fee)) / $price, 2);

kde vycházím z cílové investice např. 500 EUR ($totalPrice), odečtu fee a ze zbytku zjistím, kolik mohu koupit jednotek.

Doufám, že jsem vysvětlil význam API a nastínil základ pro implementaci pro službu COINBASE PRO.

Jako obvykle, kdyby byl jakýkoliv dotaz nebo připomínka, tak komentáře jsou vám k dispozici.

Operátor NEBO v PHP a jeho specifické použití

Výchozí situace:
Mám cyklus, kde volám funkci, která mi vrací TRUE nebo FALSE a potřebuji vědět, zda alespoň jeden průběh vrátil TRUE.

Možná to pro PHP experty nebude žádná novinka, ale pro mě jsem přišel sice na odhadnutelnou, ale i tak zajímavou konstrukci, kterou možná všichni neznáte.

$state = false;
foreach ($array as $value) {
	$state |= setParam($value); // operátor |=, funkce setParam vrací true|false
}

Není to pěkné?

Zabezpečení WordPress administrace pomocí .htaccess

Jednou mi tak volá hoster, že probíhá cílený útok na tento blog (nechci se nyní zabývat detaily). Nebojím se o sílu svého hesla, ale nadměrně to zatěžuje server.

Řešení je jednoduché!
Do souboru .htacces jsem přidal následující blok:

<IfModule mod_rewrite.c>
	RewriteEngine on
	RewriteCond %{REQUEST_URI} ^(.*)?wp-login\.php(.*)$ [OR]
	RewriteCond %{REQUEST_URI} ^(.*)?wp-admin$
	RewriteCond %{REMOTE_ADDR} !^1\.2\.3\.4$
	RewriteCond %{REMOTE_ADDR} !^4\.3\.2\.1$
	RewriteRule ^(.*)$ - [R=403,L]
</IfModule>

Toto pro IP 1.2.3.4 a 4.3.2.1.

Hotovo!

Jistě jsou i jiná řešení. Například pomocí nějakých pluginů, ale pro mě jako člověka programování znalého toto přijde nejrychlejší… A hlavně! Plugin znamená, že to bude veřejná metoda a bude jen otázka času, než se někomu vyplatí na takový prvek napsat robota, který s ním bude počítat…

Fotoalbum v NETTE (flickr style) – jak obejít databázi

Dva body, které mi vadili na starém albu:

  • složité nahrávání fotek (přes již prastarou aplikaci Olympus Camedia Photoalbum)
  • proprietální databáze Olympus Camedia Photoalbum postavená na MS ACCESS 1997, bez rozumné možnosti rozšíření

A jeden bod, který jsem měl jako požadavek na album nové:

  • minimální závislost na databázi

Když jsem psal tyto řádky netušil jsem, že se databáze budu schopen zbavit úplně (alespoň na straně uživatele). Došlo mi to ve chvíli, kdy jsem nahrával první album a následně jsem se musel přepínat do prostředí databáze a tam zadávat údaje (jméno, cesta, parent_id, …). Čím to nahradit?

INI souborem. Výhoda je, že je to i pro laika pochopitelné. Stačí do přidávané složky nahrát soubor album.ini a v něm mít následující obsah:

[album]
nazev="Vildštejn - Mohyly"
dukaz=1753
datum="5. - 6. 10. 2013"
 
[nezobrazovat]
fotka[]=DSC_9317.JPG
fotka[]=DSC_9318.JPG

Toto nepotřebuje delšího komentáře. V oddíle je zvykem mít název tvořen ve tvaru „1753 – Vildštejn – Mohyly 5. – 6. 10. 2013“ a obsah souboru je pochopitelný i pro laika.

Ještě drobné zabezpečení v .htaccess.

RewriteRule (.*)album.ini$ - [F]

Práce se souborem album.ini:
Načítání (zatím i s databází):

	public function getNameFromPath($path) {
		$row = $this->connection->fetchColumn('SELECT `desc` FROM `I_dir` WHERE `webalize-path`=? LIMIT 1', strtr($path, '/', '\\'));
		if ($row['desc'] == '') {
			$ini_array = @parse_ini_file(ALBUM_PATH . $path . 'album.ini');
			if (!isset($ini_array['nazev'])) return 'Album nemá vyplněno název';
			return iconv('WINDOWS-1250', 'UTF-8', "{$ini_array['dukaz']} - {$ini_array['nazev']} {$ini_array['datum']}");
		} else {
			return $row;
		}
	}

Ukládání:
Bude potřeba celou databázi převést na album.ini soubory a dále ve webovém rozhraní opatřit admin módem, aby šlo z rozhraní označit fotky, které nemají jít vidět směrem ven. Na webu jsem nenašel rozumnou komplexní funkci/třídu pro zápis do tohoto formátu, tak jsem si ji napsal sám.

Funkce dostane cestu k souboru a pole, které uloží do struktury. Tedy nejen že uloží, ale umí do souboru i data přidávat ne jen přepisovat.

	/**
	 *	přidá do existujícího INI souboru hodnoty ve tvaru $arr['klic']['podklic'] = $hodnota
	 *
	 */	 	 	 	
	public function saveIni($array, $path) {
		$ini_array = parse_ini_file(ALBUM_PATH . $path . 'album.ini', true);
 
		$res = array();
		foreach($ini_array as $key => $val) {
		    if(is_array($val)) {
		        $res[] = "[$key]";
		        foreach($val as $skey => $sval) {
		        	if(is_array($sval)) {
		        		foreach($sval as $skey1 => $sval1) {
							$res[] = "{$skey}[] = ".(is_numeric($sval1) ? $sval1 : '"'.$sval1.'"');
						}
					} else {
						$res[] = "$skey = ".(is_numeric($sval) ? $sval : '"'.$sval.'"');
					}
				}
				if (array_key_exists($key, $array)) {
					foreach($array[$key] as $skey => $sval) {
						if(is_array($sval)) {
			        		foreach($sval as $skey1 => $sval1) {
								$res[] = "{$skey}[] = ".(is_numeric($sval1) ? $sval1 : '"'.$sval1.'"');
							}
						} else {
							$res[] = "$skey = ".(is_numeric($sval) ? $sval : '"'.$sval.'"');
						}
					}
					unset($array[$key]);
				}
				$res[] = '';
		    } else {
				$res[] = "$key = ".(is_numeric($val) ? $val : '"'.$val.'"');
				if (array_key_exists($key, $array)) {
					$res[] = "$array[$key] = ".(is_numeric($array[$key]) ? $array[$key] : '"'.$array[$key].'"');
					unset($array[$key]);
				}
			}
		}
		foreach($array as $key => $val) {
			if(is_array($val)) {
		        $res[] = "[$key]";
		        foreach($val as $skey => $sval) {
		        	if(is_array($sval)) {
		        		foreach($sval as $skey1 => $sval1) {
							$res[] = "{$skey}[] = ".(is_numeric($sval1) ? $sval1 : '"'.$sval1.'"');
						}
					} else {
						$res[] = "$skey = ".(is_numeric($sval) ? $sval : '"'.$sval.'"');
					}
				}
				$res[] = '';
		    } else {
				$res[] = "$key = ".(is_numeric($val) ? $val : '"'.$val.'"');
			}
		}
 
		file_put_contents('safe://' . ALBUM_PATH . $path . 'album.ini', implode("\r\n", $res));
	}

Jediné co mi nyní na ni vadí je standardní funkce parse_ini_file(), která nenačte komentáře a tak o ně tímto přijdeme.