|
|
-
FXCM Rates
FXCM makes available a feed for select instruments which are not updated in real time, though are refreshed on an interval. This feed is available in three 'flavors'. The xml returned is a valid XML documents with a Rates tag as the root with a Rate tag as child elements.
http://http://rates.fxcm.com/RatesXML
Code:
<Rate Symbol="EURUSD">
<Bid>1.38694</Bid>
<Ask>1.3872</Ask>
<High>1.41729</High>
<Low>1.38683</Low>
<Direction>1</Direction>
<Last>15:22:43</Last>
</Rate>
http://http://rates.fxcm.com/RatesXML2
Code:
<Rate Symbol="EURUSD">
<Symbol>EURUSD</Symbol>
<Bid>1.3849</Bid>
<Ask>1.38509</Ask>
<High>1.41729</High>
<Low>1.38485</Low>
<Direction>0</Direction>
<Last>15:30:13</Last>
</Rate>
http://http://rates.fxcm.com/RatesXML3
Code:
<Rate Symbol="EURUSD">
<Symbol>EURUSD</Symbol>
<Bid>1.38446</Bid>
<Ask>1.38472</Ask>
<High>1.41729</High>
<Low>1.38426</Low>
<Direction>-1</Direction>
<Last>15:30:43</Last>
<Date>2011-10-31</Date>
</Rate>
With any of the three formats above, it is possible to create a web page that will access the feed at a regular interval and display the rate information using AJAX methodology. An example of code used, not compatible with Internet Explorer, to do this.
rates.js
PHP Code:
// declare global variables used in the gadget
var loading, url, rssXML;
// a 'constant' structure for the outputting of each instrument's data
// each class is defined in FXCMRates.css
// the background of the current rates section will change color depending on the direction
var strWrapper =
"<div class='instrument'>" + // create an instrument section
"<div class='identity'>" + // create an identity section
"<div class='last'>[last]</div>" + // create a section for the time of last update
"<div class='symbol'>[symbol]</div>" +// create a section to display the symbol
"<div class='date'>[date]</div>" + // create a section for the date of last update
"</div>" + // close the identity section
"<div class='rates'>" + // create a rates section
"<div class='high'>[high]</div>" + // create a section to display the high of the instrument
"<div class='current [direction]'>" + // create a current rate section
"<div class='bid'>[bid]</div>" + // create a section to display the bid rate
"<div class='ask'>[ask]</div>" + // create a section to display the ask rate
"</div>" + // close the current rate section
"<div class='low'>[low]</div>" + // create a section to display the low of the instrument
"</div>" + // close the rates section
"<div class='clear'></div>" + // create a section to ensure page alignment
"</div>"; // close the instrument section
/**
* init()
* triggered at the Load event for the 'page'
*/
function init()
{
// define the a reference to a section of the page
loading = document.getElementById("loading");
// define the url to feed to process
url = "http://rates.fxcm.com/RatesXML3";
// prime the page by calling getRSS()
getRSS();
// set a regular interval to call getRSS() evern 60 seconds
setInterval("getRSS()", 60 * 1000);
}
/**
* getRSS()
* Creates an ActiveX instance of the XMLHttpRequest object to request a remote web document to be
* accessed through a DOM.
*/
function getRSS()
{
// display a note within the loading section of the page that a connection is being attempted
loading.innerText = "Connecting...";
// define a new XMLHttpRequest object
rssObj = new XMLHttpRequest();
// define a connection to the specified url, denoting it is an asynchronous call
rssObj.open("GET", url, true);
// when state of the connection changes, perform these actions
rssObj.onreadystatechange = function()
{
// if the state is Completed (4)
if (rssObj.readyState == 4)
{
// if the status of the request is Ok (200)
if (rssObj.status == 200)
{
// create a new timestamp
now = new Date();
// define reference to the minutes
min = now.getMinutes();
// define reference to the seconds
sec = now.getSeconds();
// display a formated timestamp of the refresh
loading.innerHTML = "Last updated:<br />" +
(now.getMonth() + 1) + "/" + (now.getDate()) + "/" + (now.getFullYear()) + " " +
now.getHours() + ":" + ((min < 10) ? "0" + min : min) + ":" + ((sec < 10) ? "0" + sec : sec);
// save the response DOM as the global rssXML
rssXML = rssObj.respon---ML;
// call the function to display the new rates
parseRSS();
// if there was an error, clear the interval timer
if (chkConn) clearInterval(chkConn);
}
// othwise there may be a problem
else
{
// define a reference to a connection check
var chkConn;
// denote that the attempt failed
loading.innerText = "Unable to connect";
// set an interval to try again in 30 seconds
chkConn = setInterval("getRSS()", 30 * 1000);
}
}
// otherwise
else
// denote that the data is a being loaded
loading.innerText = "Loading...";
}
// send the request and initiate the connection
rssObj.send();
}
/**
* parseRSS()
* having recieved the external page as a DOM, traverse it to format the data to this page
*/
function parseRSS()
{
// check the preferences to see whether there should be a filter on the instruments
instrFilter = ""; // declare and prime the instrument filter
// read into the instrument filter the value of the associated preference
instrFilter = System.Gadget.Settings.readString("instrFilter");
// if the instrument filter is undefined in preferences, set the filter to all
if (instrFilter == "") instrFilter = "*";
// create a reference to the html wrapper for the instrument display
targetDiv = document.getElementById("instruments");
// create a collection of all the Rate elements in the feed
rates = rssXML.getElementsByTagName("Rate");
// clear the html wrapper of content
targetDiv.innerHTML = "";
// iterate through the Rate elements
for(i = 0; i < rates.length; i++)
{
// define which symbol currently being processed
symbol = rssXML.getElementsByTagName("Symbol")[i].childNodes[0].nodeValue;
// check to see if the symbol passes the current filter
if(instrFilter.indexOf("*") >= 0 || instrFilter.toUpperCase().indexOf(symbol) >= 0)
/**
* use javascript String.replace function and chaining to populate values into the html
* structure defined in strWrapper, appending the result to the html wrapper
*
* this occurs by referencing the appropriate tag of the same index
*/
targetDiv.innerHTML += strWrapper
.replace("[direction]", "d" + rssXML.getElementsByTagName("Direction")[i].childNodes[0].nodeValue)
.replace("[last]", rssXML.getElementsByTagName("Last")[i].childNodes[0].nodeValue)
.replace("[symbol]", symbol)
.replace("[date]", rssXML.getElementsByTagName("Date")[i].childNodes[0].nodeValue)
.replace("[high]", fxRate(rssXML.getElementsByTagName("High")[i].childNodes[0].nodeValue, symbol))
.replace("[bid]", fxRate(rssXML.getElementsByTagName("Bid")[i].childNodes[0].nodeValue, symbol))
.replace("[ask]", fxRate(rssXML.getElementsByTagName("Ask")[i].childNodes[0].nodeValue, symbol))
.replace("[low]", fxRate(rssXML.getElementsByTagName("Low")[i].childNodes[0].nodeValue, symbol))
;
}
// add an adjustment section to keep page alignment, class defined in FXCMRates.css
targetDiv.innerHTML += "<div class='clear'></div>";
}
/**
* fxRate(double, string)
* format a given rate with trailing zeros depending on the instrument symbol
*/
function fxRate(rate, symbol)
{
// ensure that the double value is a numerical value
r = parseFloat(rate);
// declare and prime the return value as a string
str = "";
// if the instrument uses the Japanese Yen, set to 3 decimal places
if(symbol.indexOf("JPY") > 0) str += r.toFixed(3);
// if the instrument uses Silver or Gold, set to 2 decimal places
else if((symbol.indexOf("XAU") >= 0) || (symbol.indexOf("XAG") >= 0)) str += r.toFixed(2);
// if the instrument is the USDOLLAR, set to 0 decimal places
else if((symbol.indexOf("DOLLAR") >= 0)) str += r.toFixed(0);
// otherwise, set to 5 decimal places
else str += r.toFixed(5);
// return an html formated string, classes defined in FXCMRates.css
return "<span class='reduce'>" + str.slice(0, -2) + "</span>" + str.slice(-2, str.length);
}
rates.htm
HTML Code:
<!DOCTYPE html>
<html>
<head>
<script type="text/jscript" language="jscript" src="rates.js"></script>
<style>
#gadgetContent
{
margin: 8px;
padding: 0;
position: relative;
text-align: center;
overflow: hidden;
}
/* #loading { color: #fff; } */
#loading, #instruments { width: 242px; height: 36px; }
#instruments, .instrument, .identity, .rates, .current { position: relative; }
.identity, .rates { width: 50%;}
.last, .high, .low, .date, .current, .symbol { height: 16px; font-size: 13px; width: 100%; }
.bid, .ask { font-size: 12px; text-align: right; width: 49%; margin-right: 1%; }
.bid .reduce, .ask .reduce { font-size: 9px; }
.symbol, .current { height: 32px; font-size: 20px; }
.identity, .rates, .bid, .ask { float:left; }
.current, .symbol { line-height: 32px; }
.d1 { background-color: #00A; color: #fff; }
.d0 { background-color: #888; color: #fff; }
.d-1 { background-color: #A00; color: #fff; }
.instruments, .instrument, .identity, .rates, .current, .last, .high, .low, .date, .symbol
{ display: block; margin: 0; padding: 0; text-align: center; }
.instrument
{
float: left;
width: 220px;
height: 64px;
border-style: inset;
border-width: 2px;
margin: 0;
}
.last, .high, .low, .date, .current, .symbol, .bid, .ask, #loading
{
color: #fff;
text-shadow: 1px 1px 1px #000;
}
#instruments
{
height: 323px;
overflow-y: auto;
margin: 0;
}
.clear { clear: both; }
</style>
</head>
<body onload="init();">
<div id="gadgetContent">
<div id="loading">loading...</div>
<div id="instruments"></div>
</div>
</body>
</html>
Please note that the core of the script is the use of the XMLHttpRequest object which connects and creates an XML DOM for the given URL, in this case http://http://rates.fxcm.com/RatesXML3. As such, for many browsers, it will not run on your local computer due to security.
Alternatively, with a few adjustments, you can create your own Adobe Air or Windows 7 Gadget based on the code above.
Richard Kichenama
API Support
|