This article is not really a debate over what is the correct tool (language) to consume a streaming web service but just one example of how TradeKing’s streaming quotes api can be handled.  There are a couple caveats to the way I implemented it (in a rush before seeing the movie ‘Flight’).  The first – you need PECL’s OAuth.  You can implement this easily without it, however I just took the example from TradeKing’s profile web service and expanded.  The key is generating the hash signature (HMAC_SHA1 in this case) and for this test, it was easier for me to just use the OAuth library I already had installed.  The second caveat is how I handled decoding HTTP/1.1 Chunked Encoding.  I just quickly pounded away at it.  My understanding is that there are a couple available libraries (one in PECL) that handle the process.

TradeKing kindly hands you either JSON or XML back via “Chunked transfer encoding“.  Before each chunk you have a hexadecimal number containing the number of characters in the chunk followed by CRLF (commonly seen as “\r\n”) then the chunked message and another CRLF.

Looks like this:

1a
{"status":"connected"}

My example connects to https://stream.tradeking.com/v1/market/quotes.json, then sends the proper headers and grabs whatever comes over the socket – echoing out usable chunks.

If you wanted to clean this script up and use it as a CLI process to feed something like Redis or a message queue, you would need to build the ‘chunk handling’ function to parse the JSON message and store it/take action on it. Then have another process handle the triggering of something else (like a trade).

You can check out the source is below or at Github.

<!--?php 
//Provide your consumer keys / tokens 
try {
      // Setup an OAuth consumer
      $oauth = new OAuth($consumer_key,$consumer_secret,OAUTH_SIG_METHOD_HMACSHA1,OAUTH_AUTH_TYPE_AUTHORIZATION);
      $oauth--->setToken($access_token,$access_secret);
      $noonce=date('U') ;
      $oauth-&gt;setNonce($noonce);
      $signature= $oauth-&gt;generateSignature("GET", "https://stream.tradeking.com/v1/market/quotes.json?symbols=". $symbols);//https://stream.tradeking.com/v1/market/quotes.xml?symbols=AAPL,QQQ,MSFT");

      $fp = fsockopen("ssl://stream.tradeking.com",443, $errno, $errstr, 30);
      if (!$fp) {
          echo "$errstr ($errno)
\n";
      } else {
          $out = "GET /v1/market/quotes.json?symbols=". $symbols ." HTTP/1.1\r\n";
          $out.="User-Agent: ThomasLoughlin.com/1.0\r\n";
          $out .= "Host: stream.tradeking.com\r\n";
          $out.="Accept: */*\r\n";
          $out.="Authorization: OAuth ";
          $out .="oauth_consumer_key=".'"' .$consumer_key .'"' .",";
          $out .="oauth_nonce=".'"' .$noonce .'"' .",";
          $out .="oauth_signature=".'"' .urlencode($signature) .'"' .",";
          $out .="oauth_signature_method=".'"' ."HMAC-SHA1" .'"' .",";
          $out .="oauth_timestamp=".'"' .date('U') .'"' .",";
          $out .="oauth_token=".'"' .$access_token .'"' .",";
          $out .="oauth_version=".'"' ."1.0" .'"' ."\r\n";
          $out .= "Connection: Close\r\n\r\n";
          fwrite($fp, $out);
          echo $out;
          sleep(2);  //Chill for a couple seconds because no one wants to be rushed
          $temp_unfinished =""; //This will hold the unfinished chunks since we are reading 512 chars at a time

          $start=false;
          while (!feof($fp)) {
              $temp = fgets($fp, 512); //read in whatever is ready

              $temp=$temp_unfinished . $temp; //add the extra that was not parsed previously.
              $temp_unfinished="";  //clear the var just to be careful - not needed but I did this fast
              if($start==false)
              {

                  /*
                   The intent of this was to trash the header information and get started with
                  the first chunk (more effective when I was using a bigger buffer
                  */
                  $data=explode("\r\n\r\n", $temp, 2);
                  if(count($data)==2)
                  {
                      $start=true;
                      $temp=$data[1];
                  }
              }

              //////////////////////
              // Since we sent HTTP/1.1, we have to handle the chunking
              //////////////////////
              $chunks=explode("\r\n",$temp);
              $count=count($chunks);
              for($i=0;$ilastResponse . "\n";
  }

?&gt;

It will output something like:
php check_price.php
GET /v1/market/quotes.json?symbols=AAPL,QQQ,MSFT,VXX HTTP/1.1
User-Agent: ThomasLoughlin.com/1.0
Host: stream.tradeking.com
Accept: */*
Authorization: OAuth oauth_consumer_key="23423ewrfrqwfqwerqtretertqr",oauth_nonce="1351900465",oauth_signature="dsafasdfERWEEFdfsdrewrwer%3D",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1351900465",oauth_token="245624562rtewegwergwergwerg",oauth_version="1.0"
Connection: Close

This chunk can be handled:{"status":"connected"}
------------------
This chunk can be handled:{"trade":{"cvol":"44079982","datetime":"2012-11-02T19:54:03-04:00","exch":"Pacific","last":"65.04","symbol":"QQQ","tcond":"57,16,10","timestamp":"1351900443","vl":"100","vwap":"65.9048"}}
------------------
This chunk can be handled:{"quote":{"ask":"29.49","asksz":"6","bid":"29.48","bidsz":"10","datetime":"2012-11-02T19:54:49-04:00","exch":"Pacific","qcond":"Regular, two-sided open quote automated","symbol":"MSFT","timestamp":"1351900489"}}


Leave a Reply