Private Proxies – Buy Cheap Private Elite USA Proxy + 50% Discount!Private Proxies – Buy Cheap Private Elite USA Proxy + 50% Discount!Private Proxies – Buy Cheap Private Elite USA Proxy + 50% Discount!Private Proxies – Buy Cheap Private Elite USA Proxy + 50% Discount!
    0
  •   was successfully added to your cart.
  • Home
  • Buy proxies
  • Extra features
  • Help
  • Contact
  • Login
  • 50% OFF
    BUY NOW!
    50
    PROXIES
    $19
    --------------------
    BUY NOW!
    BUY NOW!
    BUY NOW!
    BUY NOW!
    BUY NOW!
    $29
    $49
    $109
    $179
    $299
    --------------------
    --------------------
    --------------------
    --------------------
    --------------------
    PROXIES
    PROXIES
    PROXIES
    PROXIES
    PROXIES
    100
    200
    500
    1,000
    2,000
    TOP SELLER
    BEST VALUE
    For All Private Proxies!

This task was to display stock data from Quandl. It downloads the available tickers for a certain day, displays them and lets the user choose one, then it downloads the pricing data and draws candles on a canvas.

The first problem I ran into was CORS. I’m not sure whether I’m misusing their API or if they don’t want to specifically allow it, that was solved by using a proxy. The other thing I’m still not sure about is the fact that it doesn’t work on Firefox, but works on Chromium. From what I’ve read, it seems Firefox doesn’t allow ajax calls from file:// pages. If someone could shed some light on that, it would be great.

Apart from the problems listed at the top of the page, I would like to receive reviews regarding the JavaScript, if you can clarify the issues I mentioned above too, even better.

script.js

/*   Known problems:    - non-trading dates will not display any tickers   - dates in the future can be chosen   - no date validation (Chrome takes care of it though)   - Firefox doesn't appear to allow XMLHttpRequest from file://something.html   (https://stackoverflow.com/q/5005960) */  var chartApp = function() {  const apiKey = ''; const corsProxy = 'https://cors-anywhere.herokuapp.com/'; const candleSize = 15; const candleMargin = 3; const resizeTimeout = 100;  var Candle = {   line: {     y0: 0,     y1: 0   },   box: {     y0: 0,     y1: 0   },   color: 'gray' };  var CandleData = {   open: 0,   close: 0,   low: 0,   high: 0 };  var StockDay = {   date: null,   open: 0,   close: 0,   low: 0,   high: 0 };  var state = {   tickers: [],    // A, AA ...   chartData: [],  // information for each candle   baseDate: null,   basePrice: 0,   // bottom $    maxPrice: 0,   slots: 0,       // how many candles fit in the canvas   m: 0,           // basePrice + y * m = priceAtY   timeout: null,  // clear and set timeout };  // avoid calling document.getElementBy* all the time var pcs = {   controls: null,   date: null,   tickers: null,   priceInfo: null,   dateAtCursor: null,   priceAtCursor: null,   openAtCursor: null,   closeAtCursor: null,   lowAtCursor: null,   highAtCursor: null,   chart: null,   chartCtx: null, };  function init() {   pcs.controls = byId('controls');   pcs.date = byId('startDate');   pcs.tickers = byId('tickers');   pcs.priceInfo = byId('priceInfo');   pcs.dateAtCursor = byId('dateAtCursor');   pcs.priceAtCursor = byId('priceAtCursor');   pcs.openAtCursor = byId('openAtCursor');   pcs.closeAtCursor = byId('closeAtCursor');   pcs.lowAtCursor = byId('lowAtCursor');   pcs.highAtCursor = byId('highAtCursor');   pcs.chart = byId('chart');   pcs.chartCtx = pcs.chart.getContext('2d');    pcs.date.addEventListener('change', dateChangeHandler);   pcs.tickers.addEventListener('change', tickerChangeHandler);   window.addEventListener('resize', windowResizeHandler);   reset(); }  function reset() {   pcs.priceInfo.style.display = 'none';   pcs.tickers.disabled = true;   pcs.tickers.innerHTML = '<option>choose one</option>';    setupCanvas(); }  function clearCanvas() {   pcs.chartCtx.fillStyle = 'black';   pcs.chartCtx.fillRect(0, 0, pcs.chart.width, pcs.chart.height);   pcs.chartCtx.fill(); }  function setupCanvas() {   // make 1 unit match 1px   pcs.chart.width = pcs.chart.clientWidth;   pcs.chart.height = pcs.chart.clientHeight;    // make y start at bottom   pcs.chartCtx.translate(0, pcs.chart.height);   pcs.chartCtx.scale(1, -1);    clearCanvas();   state.slots = Math.floor(pcs.chart.width / (candleSize + candleMargin)); }  function displayTickers() {   var option;   var i;    pcs.tickers.innerHTML = '<option>choose one</option>';    for (i = 0; i < state.tickers.length; i++) {     option = document.createElement('option');     option.innerText = state.tickers[i];     pcs.tickers.appendChild(option);   }    pcs.tickers.disabled = false; }  function queryAvailableTickers() {   var start = pcs.date.value; // TODO validate user input   var url = corsProxy +             'https://www.quandl.com/api/v3/datatables/WIKI/PRICES.json?' +             'date=' + start + '&qopts.columns=ticker&api_key=' + apiKey;    // parse JSON and store the list of tickers   function getTickers(data) {     var obj = JSON.parse(data);     var tickers = obj.datatable.data;     var i;      // remove any previous tickers     state.tickers = [];      for (i = 0; i < tickers.length; i++) {       state.tickers.push(tickers[i][0]);     }   }    function queryTickersCb(data) {     getTickers(data);     displayTickers();   }    sendAjaxRequest('GET', url, queryTickersCb); }  function queryTickerData() {   var ticker = pcs.tickers.value;   if (ticker === 'choose one') {     return;   }    // start date   state.baseDate = new Date(pcs.date.value);   var startStr = getDateStr(state.baseDate);    // end date   var endDate = new Date(pcs.date.value);   endDate.setDate(endDate.getDate() + state.slots);   var endStr = getDateStr(endDate);    var url = corsProxy +             'https://www.quandl.com/api/v3/datatables/WIKI/PRICES?' +             'date.gte=' + startStr + '&date.lt=' + endStr +             '&ticker=' + ticker + '&qopts.columns=date,open,close,low,high' +             '&api_key=' + apiKey;    // store daily data for tickers   function getTickerData(data) {     var obj = JSON.parse(data);     var i;     var day;     var minPrice = Number.MAX_VALUE;     var maxPrice = -1;     var data = obj.datatable.data;      state.chartData = [];     for (i = 0; i < data.length; i++) {       day = Object.create(StockDay);       day.date = new Date(data[i][0]);       day.open = data[i][1];       day.close = data[i][2];       day.low = data[i][3];       day.high = data[i][4];        if (day.low < minPrice) {         minPrice = day.low;       }        if (day.high > maxPrice) {         maxPrice = day.high;       }        state.chartData[getDateStr(day.date)] = day;     }      setLowHigh(minPrice, maxPrice);   }    function tickerDataCb(data) {     getTickerData(data);     drawTickers();     turnDisplayOn();   }    sendAjaxRequest('GET', url, tickerDataCb); }  function drawTickers() {   var i, date, key, day, x;   var candle = Object.create(Candle);    clearCanvas();    for (i = 0; i < state.slots; i++) {     date = new Date(pcs.date.value);     date.setDate(date.getDate() + i);     key = getDateStr(date);      day = state.chartData[key];      if (typeof day !== 'undefined') {       candle.line.y0 = priceToY(day.low);       candle.line.y1 = priceToY(day.high);       candle.box.y0 = priceToY(day.open);       candle.box.y1 = priceToY(day.close);       candle.color = (day.open > day.close) ? 'red' : 'green';        x = (day.date.getTime() - state.baseDate.getTime()) / 86400000;       drawCandle(x, candle);     }   } }  function drawCandle(x, candle) {   var x0 = x * (candleSize + candleMargin);   var y0 = candle.box.y0;   var y1 = candle.box.y1;    if (y0 > y1) {     y1 = y0;     y0 = candle.box.y1;   }    var height = y1 - y0;   x = Math.floor(x0 + candleSize / 2);    // line   pcs.chartCtx.strokeStyle = 'white';   pcs.chartCtx.beginPath();   pcs.chartCtx.lineTo(x, candle.line.y0);   pcs.chartCtx.lineTo(x, candle.line.y1);   pcs.chartCtx.closePath();   pcs.chartCtx.stroke();    // box   pcs.chartCtx.fillStyle = candle.color;   pcs.chartCtx.fillRect(x0, y0, candleSize, height);   pcs.chartCtx.fill(); }  function priceToY(p) {   return (p - state.basePrice) / state.m; }  function getPriceAtY(y) {   return state.basePrice + y * state.m; }  function getDiscreteX(x) {   return Math.floor(x / (candleSize + candleMargin)); }  function turnDisplayOff() {   pcs.chart.removeEventListener('mousemove', mouseMoveHandler);   pcs.priceInfo.style.display = 'none'; }  function turnDisplayOn() {   mouseMoveHandler({clientX: 0, clientY: 0});   pcs.chart.addEventListener('mousemove', mouseMoveHandler);   pcs.priceInfo.style.display = 'inline-block'; }  function setLowHigh(low, high) {   var usableHeight = pcs.chart.height - (pcs.controls.offsetHeight + 16);   state.m = (high - low) / usableHeight;   state.basePrice = low;   state.maxPrice = high; }  function mouseMoveHandler(ev) {   // compute price at Y   var y = pcs.chart.height - ev.clientY;   var price = getPriceAtY(y).toFixed(2);    // compute date at X   var x = getDiscreteX(ev.clientX);   var date = new Date(pcs.date.value);   date.setDate(date.getDate() + x);   var dateStr = getDateStr(date);    // get chart at cursor   var day = state.chartData[dateStr];    // update bar   pcs.priceAtCursor.innerText = '$ ' + price;   pcs.dateAtCursor.innerText = dateStr;    // non-trading days aren't stored   if (typeof day !== 'undefined') {     pcs.openAtCursor.innerText = '$ ' + day.open;     pcs.closeAtCursor.innerText = '$ ' + day.close;     pcs.lowAtCursor.innerText = '$ ' + day.low;     pcs.highAtCursor.innerText = '$ ' + day.high;   } }  function dateChangeHandler() {   reset();   turnDisplayOff();   queryAvailableTickers(); }  function tickerChangeHandler() {   turnDisplayOff();   setupCanvas();   queryTickerData(); }  function lastResize() {   state.timeout = null;    tickerChangeHandler(); }  function windowResizeHandler() {   if (state.timeout !== null) {     clearTimeout(state.timeout);   }    state.timeout = setTimeout(lastResize, resizeTimeout); }  // the functions below would ideally come from a library function byId(id) {   return document.getElementById(id); }  function sendAjaxRequest(method, url, cb, userErrCb) {   var req = new XMLHttpRequest();   var errCb = (typeof userErrCb !== 'undefined') ? userErrCb : defaultErrCb;    function defaultErrCb() {     console.log('ajax error');   }    function stateChangeHandler() {     if (req.readyState === 4) {       if (req.status === 200) {         cb(req.responseText);       }       else {         errCb();       }     }   }    req.open(method, url);   req.send();   req.onreadystatechange = stateChangeHandler; }  function getDateStr(date) {   var month = '' + (date.getMonth() + 1);   if (month.length != 2) {     month = '0' + month;   }    var day = '' + date.getDate();   if (day.length != 2) {     day = '0' + day;   }    return date.getFullYear() + '-' + month + '-' + day; }  function run() {   init(); }  return {   run };  }();  chartApp.run(); 

index.html

<!doctype html> <html> <head>   <meta charset="utf-8">   <title>Chart Task</title>   <link rel="stylesheet" type="text/css" href="style.css"> </head> <body>   <noscript>Please turn JavaScript on</noscript>   <div id="controls">     <form>       <p>Start date:</p>       <input type="date" id="startDate" placeholder="yyyy-mm-dd">        <p>Ticker:</p>       <select id="tickers"></select>     </form>      <div id="priceInfo">       <p>Date: <span id="dateAtCursor"></span></p>       <p>Price: <span id="priceAtCursor"></span></p>       <p>Open: <span id="openAtCursor"></span></p>       <p>Close: <span id="closeAtCursor"></span></p>       <p>Low: <span id="lowAtCursor"></span></p>       <p>High: <span id="highAtCursor"></span></p>     </div>   </div>   <canvas id="chart"></canvas>   <script src="script.js"></script> </body> </html> 

style.css

* {   margin:0;   padding:0; }  html, body {   height:100%;   width:100%;   background-color:#fff;   color:#000;   font-family:sans-serif;   font-size:0; }  #controls {   position:absolute;   background-color: #494949;   color:#fff;   width:100%;   font-size:16px;   padding:8px;   box-sizing: border-box;   z-index:2; }  #controls * {   display:inline-block; }  #controls p {   padding-left: 8px;   border-left:1px solid #fff; }  canvas {   position:absolute;   width:100%;   height:100%;   cursor:crosshair;   z-index:0; } 

screenshot

enter image description here

✓ Extra quality

ExtraProxies brings the best proxy quality for you with our private and reliable proxies

✓ Extra anonymity

Top level of anonymity and 100% safe proxies – this is what you get with every proxy package

✓ Extra speed

1,ooo mb/s proxy servers speed – we are way better than others – just enjoy our proxies!

50 proxies

$19/month

50% DISCOUNT!
$0.38 per proxy
✓ Private
✓ Elite
✓ Anonymous
Buy now

100 proxies

$29/month

50% DISCOUNT!
$0.29 per proxy
✓ Private
✓ Elite
✓ Anonymous
Buy now

200 proxies

$49/month

50% DISCOUNT!
$0.25 per proxy
✓ Private
✓ Elite
✓ Anonymous
Buy now

500 proxies

$109/month

50% DISCOUNT!
$0.22 per proxy
✓ Private
✓ Elite
✓ Anonymous
Buy now

1,000 proxies

$179/month

50% DISCOUNT!
$0.18 per proxy
✓ Private
✓ Elite
✓ Anonymous
Buy now

2,000 proxies

$299/month

50% DISCOUNT!
$0.15 per proxy
✓ Private
✓ Elite
✓ Anonymous
Buy now

USA proxy location

We offer premium quality USA private proxies – the most essential proxies you can ever want from USA

100% anonymous

Our proxies have TOP level of anonymity + Elite quality, so you are always safe and secure with your proxies

Unlimited bandwidth

Use your proxies as much as you want – we have no limits for data transfer and bandwidth, unlimited usage!

Superfast speed

Superb fast proxy servers with 1,000 mb/s speed – sit back and enjoy your lightning fast private proxies!

99,9% servers uptime

Alive and working proxies all the time – we are taking care of our servers so you can use them without any problems

No usage restrictions

You have freedom to use your proxies with every software, browser or website you want without restrictions

Perfect for SEO

We are 100% friendly with all SEO tasks as well as internet marketing – feel the power with our proxies

Big discounts

Buy more proxies and get better price – we offer various proxy packages with great deals and discounts

Premium support

We are working 24/7 to bring the best proxy experience for you – we are glad to help and assist you!

Satisfaction guarantee

24/7 premium support, free proxy activation and 100% safe payments! Best reliability private proxies for your needs!

Best Proxy Packs

  • 2,000 Private Proxies $600.00 $299.00 / month
  • 1,000 Private Proxies $360.00 $179.00 / month

Quick Links

  • More information
  • Contact us
  • Privacy Policy
  • Terms and Conditions

Like And Follow Us


Copyright ExtraProxies.com | All Rights Reserved.
  • Checkout
  • Contact
  • Help
  • Home
  • My Account
  • My Cart
  • News
  • Privacy Policy
  • Proxy features
  • Proxy packs
  • Terms and Conditions
Private Proxies – Buy Cheap Private Elite USA Proxy + 50% Discount!
    0 items