├── .gitignore ├── .travis.yml ├── LICENSE.md ├── README.md ├── composer.json ├── config └── currencyConverter.php ├── phpunit.xml ├── src ├── CConverter.php ├── CConverterServiceProvider.php ├── Currency.php ├── CurrencyProvider.php └── Providers │ ├── BaseProvider.php │ ├── CurrencyLayer.php │ ├── EuropeanCentralBank.php │ ├── Fixer.php │ ├── OpenExchange.php │ ├── ProviderInterface.php │ └── Rates.php └── tests ├── CurrencyConvertTest.php ├── currencyLayerTestData.json ├── europeanCentralBankTestData.json ├── fixerTestData.json ├── openExchangeTestData.json └── yahooTestData.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .AppleDouble 3 | .LSOverride 4 | 5 | # Icon must end with two \r 6 | Icon 7 | 8 | # Thumbnails 9 | ._* 10 | 11 | # Files that might appear in the root of a volume 12 | .DocumentRevisions-V100 13 | .fseventsd 14 | .Spotlight-V100 15 | .TemporaryItems 16 | .Trashes 17 | .VolumeIcon.icns 18 | 19 | # Directories potentially created on remote AFP share 20 | .AppleDB 21 | .AppleDesktop 22 | Network Trash Folder 23 | Temporary Items 24 | .apdisk 25 | 26 | # Created by .ignore support plugin (hsz.mobi) 27 | .idea 28 | vendor 29 | .env 30 | .env.testing -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - 7.3 4 | before_script: 5 | - composer install --no-interaction 6 | script: 7 | - vendor/bin/phpunit --coverage-clover=coverage.xml 8 | after_success: 9 | - bash <(curl -s https://codecov.io/bash) -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 Daniel Mellum 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Currency Converter 2 | 3 | [![GitHub](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](https://github.com/danielme85/laravel-cconverter) 4 | [![PHP from Packagist](https://img.shields.io/packagist/php-v/danielme85/laravel-cconverter.svg?style=flat-square)](https://packagist.org/packages/danielme85/laravel-cconverter) 5 | [![GitHub release](https://img.shields.io/github/release/danielme85/laravel-cconverter.svg?style=flat-square)](https://packagist.org/packages/danielme85/laravel-cconverter) 6 | [![GitHub tag](https://img.shields.io/github/tag/danielme85/laravel-cconverter.svg?style=flat-square)](https://github.com/danielme85/laravel-cconverter) 7 | [![Travis (.org)](https://img.shields.io/travis/danielme85/laravel-cconverter.svg?style=flat-square)](https://travis-ci.org/danielme85/laravel-cconverter) 8 | [![Codecov](https://img.shields.io/codecov/c/github/danielme85/laravel-cconverter.svg?style=flat-square)](https://codecov.io/gh/danielme85/laravel-cconverter) 9 | 10 | A simple currency conversion plug-in for Laravel 5.5+ 💵
11 | Example usage: https://danielmellum.com/projects/currency-converter 12 | 13 | Version testing and requirements 14 | 15 | | Version | Tested with | 16 | | :----------: |:-------------:| 17 | | dev-master | Laravel 6.0 | 18 | | v0.3.* | Laravel 6.0 | 19 | | v0.2.* | Laravel 5.6 | 20 | | v0.1.* | Laravel 5.5 | 21 | | v0.0.7 | Laravel 5.4 | 22 | 23 | If you are having composer requirement issues using the latest release and Laravel < v5.4, try the v0.0.7 release. 24 | 25 | Please note: 26 | * The European Central Bank does not require any user account and is therefore set as the default 'api-source', 27 | however the number of available currencies are somewhat limited compared to the other commercial sources (37). 28 | In my experience this source is also unpredictable, and might give an empty response. 29 | * All the other data providers are commercial and require a user account. They all have a free tier of 1000 requests per month, 30 | let's say you theoretically cache results for 60 min and you should be covered with some margin for errors 👍 31 | Coincidentally Cache is enabled per default and set to 60 min. Now in theory one should perhaps make a simple Eloquent Model with 32 | the columns: date, from, to, rate or something similar, and then store the historical results. Please note that depending on usage this 33 | might go against the user agreements on the commercial data providers. 🤫 🙈 34 | 35 | ### Installation 36 | ``` 37 | composer require danielme85/laravel-cconverter 38 | ``` 39 | 40 | ### Configuration 41 | You can publish this vendor config file if you would like to make changes to the default config. 42 | ``` 43 | php artisan vendor:publish --provider="danielme85\CConverter\CConverterServiceProvider" 44 | ``` 45 | 46 | All config variables can also be changed in your local .env file: 47 | ``` 48 | CC_API_SOURCE=eurocentralbank 49 | CC_USE_SSL=true 50 | CC_FIXERIO_ACCESS_KEY= 51 | CC_OPENEXCHANGE_APP_ID= 52 | CC_CURRENCYLAYER_ACCESS_KEY= 53 | CC_ENABLE_LOG=false 54 | CC_ENABLE_CACHE=true 55 | CC_CACHE_TIMEOUT=60 56 | ``` 57 | 58 | ### Usage 59 | There are static class "shortcuts" to convert or get one-time Currency series. 60 | ```php 61 | //To convert a value 62 | $valueNOK = Currency::conv($from = 'USD', $to = 'NOK', $value = 10, $decimals = 2); 63 | 64 | //To convert a value based on historical data 65 | $valueNOK = Currency::conv($from = 'USD', $to = 'NOK', $value = 10, $decimals = 2, $date = '2018-12-24'); 66 | 67 | //to get an array of all the rates associated to a base currency. 68 | $rates = Currency::rates(); //defaults to USD 69 | 70 | $rates = Currency::rates('NOK'); 71 | 72 | //Get historical rates 73 | $rates = Currency::rates('NOK', '2018-12-24'); 74 | 75 | ``` 76 | 77 | #### Working with multiple values 78 | I would highly recommend creating a model instance and the non-static functions getRates() & convert() when doing 79 | multiple conversion or getting multiple currency series for the best performance. The currency rates are stored 80 | in the provider model by date/base-currency for quick and easy access. 81 | 82 | ```php 83 | $currency = new Currency(); 84 | $values = [1, 3, 4, 5...]. 85 | foreach ($values as $value) { 86 | $valueNOK = $currency->convert($from = 'USD', $to = 'NOK', $value = 10, $decimals = 2); 87 | } 88 | 89 | $rates = $currency->getRates('NOK'); 90 | foreach ($rates as $rate) { 91 | $value = $valueNOK * $rate; 92 | } 93 | ``` 94 | 95 | You can override the settings when/if you create a new instance. 96 | ```php 97 | $currency = new Currency( 98 | $api = 'yahoo', 99 | $https = false, 100 | $useCache = false, 101 | $cacheMin = 0); 102 | ... 103 | $result = Currency:conv( 104 | $from = 'USD', 105 | $to = 'NOK', 106 | $value = 10, 107 | $decimals = 2, 108 | $date = '2018-12-24', 109 | $api = 'yahoo', 110 | $https = false, 111 | $useCache = false, 112 | $cacheMin = 0); 113 | ``` 114 | 115 | Use the three lettered ISO4217 code for to/from currencies: http://en.wikipedia.org/wiki/ISO_4217 116 | 117 | #### Money Formatting 118 | The package: gerardojbaez/money is included for an easier and more powerful Money Formatter, excellent alternative to money_format(). 119 | You can get the values of an conversion by setting round='money' (money formatter overrides rounding). 120 | ```php 121 | Currency::conv('USD', 'USD', 10, 2); 122 | //Result: 10 123 | Currency::conv('USD', 'USD', 10, 'money'); 124 | //Result: $10.00 125 | $currency->convert('USD', 'USD', 10, 'money'); 126 | //Result: $10.00 127 | ``` 128 | You can also get the money formatter itself trough the static Currency function: 129 | ```php 130 | $formater = Currency::money($amount = 0, $currency = 'USD'); 131 | ``` 132 | This Money Formatter also ships with a handy helper function. 133 | ```php 134 | echo moneyFormat(10, 'USD'); 135 | //Result: $10.00 136 | 137 | ``` 138 | See Money Formatter github page for more information and usage. 139 | https://github.com/gerardojbaez/money 140 | 141 | ### Supported functions per API 142 | Default API is: The European Central Bank 143 | 144 | | Config var | API | HTTPS | Historical | Sign-up required | URL | 145 | | ----------------- | -------------------------- |:------------: | :---------: | :--------------: | ----------------------- | 146 | |eurocentralbank | The European Central Bank | yes | yes | no | https://sdw-wsrest.ecb.europa.eu/help/ | 147 | |openexchange | OpenExchangeRates.com | non-free | non-free | yes | https://openexchangerates.org | 148 | |currencylayer | *CurrencyLayer | non-free | yes | yes | https://currencylayer.com | 149 | |fixer | *Fixer.io | yes | yes | yes | https://fixer.io | 150 | 151 | *CurrencyLayer and Fixer.io is the same company now, and it seems like the services have become one and the same. 152 | 153 | ### Disclaimer 154 | Please take note of the Terms of Use for the different data sources. 155 |
156 | https://policies.yahoo.com/us/en/yahoo/terms/product-atos/yql/index.htm 157 |
158 | https://currencylayer.com/terms 159 |
160 | https://openexchangerates.org/terms 161 | 162 | This code is released per the MIT open source license: http://opensource.org/licenses/MIT 163 | The actual rates and conversion will vary between the data sources. 164 | In addition I am no math professor, so you should probably not use this for super serious multi-billion dollar investments. 165 | If you are gonna spend your hard earned billion dollars on the money market, you should probably use something like this: http://www.forex.com/forex.html 166 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "danielme85/laravel-cconverter", 3 | "description": "Laravel 5 plug-in for currency conversion", 4 | "keywords": ["laravel","laravel-5", "currency", "conversion", "finance"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Daniel Mellum", 9 | "email": "mellum@gmail.com" 10 | } 11 | ], 12 | "require": { 13 | "illuminate/support": ">=5.4", 14 | "guzzlehttp/guzzle": ">=7.0", 15 | "gerardojbaez/money": ">=0.3" 16 | }, 17 | "require-dev": { 18 | "orchestra/testbench": ">=4.0" 19 | }, 20 | "autoload": { 21 | "psr-4": { 22 | "danielme85\\CConverter\\": "src" 23 | } 24 | }, 25 | "extra": { 26 | "laravel": { 27 | "providers": [ 28 | "danielme85\\CConverter\\CConverterServiceProvider" 29 | ], 30 | "aliases": { 31 | "Currency": "danielme85\\CConverter\\CConverter" 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /config/currencyConverter.php: -------------------------------------------------------------------------------- 1 | env('CC_API_SOURCE', 'eurocentralbank'), 21 | 22 | /* 23 | |-------------------------------------------------------------------------- 24 | | OpenExchangeRates App ID 25 | |-------------------------------------------------------------------------- 26 | | 27 | | Your app id from openexchangerates.org 28 | | 29 | */ 30 | 31 | 'openex-app-id' => env('CC_OPENEXCHANGE_APP_ID', ''), 32 | 33 | /* 34 | |-------------------------------------------------------------------------- 35 | | CurrencyLayer API Access Key 36 | |-------------------------------------------------------------------------- 37 | | 38 | | Your API access key for currencylayer.com 39 | | 40 | */ 41 | 42 | 'currencylayer-access-key' => env('CC_CURRENCYLAYER_ACCESS_KEY', ''), 43 | 44 | /* 45 | |-------------------------------------------------------------------------- 46 | | Fixer.io API Access Key 47 | |-------------------------------------------------------------------------- 48 | | 49 | | Your API access key for fixer.io 50 | | 51 | */ 52 | 53 | 'fixer-access-key' => env('CC_FIXERIO_ACCESS_KEY', ''), 54 | 55 | /* 56 | |-------------------------------------------------------------------------- 57 | | Enable SSL / HTTPS 58 | |-------------------------------------------------------------------------- 59 | | 60 | | Use ssl/https when getting data from the data sources. 61 | | The free version of OpenExchangeRates does NOT support https :( 62 | | 63 | */ 64 | 65 | 'use-ssl' => env('CC_USE_SSL', true), 66 | 67 | /* 68 | |-------------------------------------------------------------------------- 69 | | OpenExchangeRates User "real" base value 70 | |-------------------------------------------------------------------------- 71 | | 72 | | When using the free account we can still calculate other currencies based 73 | | on USD as a base thanks to some basic math. 74 | | 75 | | If you do not want this behavior for OpenExchangeRates set this to true 76 | | and 'real' base values are used instead of calculated ones. This requires 77 | | an 'enterprise account' on OpenExchangeRates. 78 | | 79 | */ 80 | 81 | 'openex-use-real-base' => env('CC_USE_REAL_BASE', false), 82 | 83 | /* 84 | |-------------------------------------------------------------------------- 85 | | Fixer.io use "real" base value 86 | |-------------------------------------------------------------------------- 87 | | 88 | | When using the free account we can still calculate other currencies based 89 | | on EUR as a base thanks to some basic math. 90 | | 91 | | enable this if you want real base values instead of calculated ones. 92 | | Requires payed account on fixer.io 93 | | 94 | */ 95 | 96 | 'fixer-use-real-base' => env('CC_USE_REAL_BASE_FIXER', false), 97 | 98 | /* 99 | |-------------------------------------------------------------------------- 100 | | Enable Cache 101 | |-------------------------------------------------------------------------- 102 | | 103 | | Enable the Laravel cache engine to cache the currency rates. 104 | | 105 | | https://laravel.com/docs/5.8/cache 106 | | 107 | */ 108 | 109 | 'enable-cache' => env('CC_ENABLE_CACHE', true), 110 | 111 | /* 112 | |-------------------------------------------------------------------------- 113 | | Cache Timeout 114 | |-------------------------------------------------------------------------- 115 | | 116 | | Number of minutes before the cached rates expires. 117 | | 118 | | https://laravel.com/docs/5.8/cache 119 | | 120 | */ 121 | 122 | 'cache-min' => env('CC_CACHE_TIMEOUT', 60), 123 | 124 | /* 125 | |-------------------------------------------------------------------------- 126 | | Enable Detailed Log 127 | |-------------------------------------------------------------------------- 128 | | 129 | | Log more detailed debug output like caching and when rates are fetched. 130 | | 131 | */ 132 | 133 | 'enable-log' => env('CC_ENABLE_LOG', false), 134 | 135 | ); -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ./src 6 | 7 | 8 | ./vendor 9 | 10 | 11 | 12 | 13 | ./tests/ 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/CConverter.php: -------------------------------------------------------------------------------- 1 | mergeConfigFrom(__DIR__.'/../config/currencyConverter.php', 'currencyConverter'); 38 | $this->publishes([ 39 | __DIR__ . '/../config/currencyConverter.php' => config_path('currencyConverter.php') 40 | ]); 41 | } 42 | 43 | /** 44 | * Register the application services. 45 | * 46 | * @return void 47 | */ 48 | public function register() 49 | { 50 | $this->app->bind('Currency', function() 51 | { 52 | return new Currency(); 53 | }); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/Currency.php: -------------------------------------------------------------------------------- 1 | api = $settings['api-source']; 51 | $this->cacheEnabled = $settings['enable-cache']; 52 | $this->cacheMinutes = $settings['cache-min']; 53 | $this->logEnabled = $settings['enable-log']; 54 | 55 | try { 56 | $this->provider = CurrencyProvider::getProvider($this->api, $settings); 57 | } catch (\Exception $e) { 58 | 59 | } 60 | } 61 | 62 | /** 63 | * Get currency rates in an array format 64 | * 65 | * @param null|string $base The base currency (defaults to USD if null/empty). 66 | * @param null|string $date The date (defaults to today if null/empty). 67 | * 68 | * @return array 69 | */ 70 | public function getRates($base = null, $date = null) : array 71 | { 72 | $rates = $this->getRateModel($base, $date); 73 | 74 | return $rates->toArray(); 75 | } 76 | 77 | /** 78 | * Get currency rates in an array format 79 | * 80 | * @param null|string $base The base currency (defaults to USD if null/empty). 81 | * @param null|string $date The date (defaults to today if null/empty). 82 | * 83 | * @return array 84 | */ 85 | public function getRateResults($base = null, $date = null) : array 86 | { 87 | $rates = $this->getRateModel($base, $date); 88 | 89 | return $rates->rates; 90 | } 91 | 92 | /** 93 | * Get the Rates object from the Provider 94 | * 95 | * @param null|string $base 96 | * @param null|string $date 97 | * 98 | * @return Rates 99 | */ 100 | public function getRateModel($base = null, $date = null) : Rates 101 | { 102 | $base = strtoupper($base); 103 | if (empty($base)) { 104 | $base = 'USD'; 105 | } 106 | if (empty($date)) { 107 | $date = date('Y-m-d'); 108 | } 109 | $this->fromCache = false; 110 | $api = $this->api; 111 | 112 | if ($this->cacheEnabled) { 113 | $cachekey = "cc-$api-$base-$date"; 114 | 115 | $rates = Cache::get($cachekey); 116 | if (is_object($rates) and isset($rates->rates)) { 117 | $this->fromCache = true; 118 | if ($this->logEnabled) { 119 | Log::debug("Got currency rates from cache: $cachekey"); 120 | } 121 | } 122 | else { 123 | $rates = $this->provider->rates($base, $date); 124 | if (!empty($rates->rates)) { 125 | if(Cache::add($cachekey, $rates, now()->addMinutes($this->cacheMinutes)) and $this->logEnabled) { 126 | Log::debug('Added new currency rates to cache: '.$cachekey.' for '.$this->cacheMinutes.' min.'); 127 | } 128 | } 129 | } 130 | } 131 | else { 132 | $rates = $this->provider->rates($base, $date); 133 | } 134 | 135 | if (empty($rates->rates)) { 136 | Log::warning("$rates->error -> $rates->url"); 137 | } 138 | 139 | return $rates; 140 | } 141 | 142 | 143 | /** 144 | * Convert a from one currency to another 145 | * 146 | * @param string $from ISO4217 country code 147 | * @param string $to ISO4217 country code 148 | * @param mixed $value calculate from this number 149 | * @param integer|string $round round this this number of decimals or use money formatter. 150 | * @param null|string $date date for historical data 151 | * 152 | * @return float|string $result 153 | */ 154 | public function convert($from, $to, $value, $round = 2, $date = null) 155 | { 156 | $result = 0; 157 | $from = strtoupper($from); 158 | $to = strtoupper($to); 159 | 160 | if (empty($value)) { 161 | return $result; 162 | } 163 | 164 | $rates = $this->getRateResults($from, $date); 165 | 166 | if (!empty($rates)) { 167 | if (!array_key_exists($to, $rates)) { 168 | Log::warning("The currency $to does not exist for the provider: $this->api"); 169 | return $result; 170 | } 171 | $rate = $rates[$to]; 172 | 173 | if ($from === 'USD') { 174 | //All currencies are stored in the model has USD as base currency 175 | $result = $value * $rate; 176 | } 177 | else { 178 | //Convert Currencies via USD 179 | $result = $rate * ($value/$rates[$from]); 180 | } 181 | 182 | if ($round === 'money') { 183 | $result = moneyFormat($result, $to); 184 | } 185 | else if ($round or $round === 0) { 186 | $result = round($result, $round); 187 | } 188 | } 189 | else { 190 | Log::warning("No rates for $from found from provider: $this->api"); 191 | return $result; 192 | } 193 | return $result; 194 | } 195 | 196 | /** 197 | * Convert a from one currency to another 198 | * 199 | * @param string $from ISO4217 country code 200 | * @param string $to ISO4217 country code 201 | * @param mixed $value calculate from this number 202 | * @param null|integer|string $round round this this number of decimals, or use 'money' for money formatter. 203 | * @param null|string $date date for historical data 204 | * @param null|string $api override Provider setting, 205 | * @param null|bool $https override https setting 206 | * @param null|bool $useCache override cache setting 207 | * @param null|int $cacheMin override cache setting 208 | * @param null|bool $runastest for testing, uses local test data. 209 | * 210 | * @return mixed $result 211 | */ 212 | public static function conv($from, $to, $value, $round = null, $date = null, $api = null, $https = null, 213 | $useCache = null, $cacheMin = null, $runastest = false) 214 | { 215 | $convert = new self($api, $https, $useCache, $cacheMin, $runastest); 216 | return $convert->convert($from, $to, $value, $round, $date); 217 | } 218 | 219 | 220 | /** 221 | * Get rates for given currency an optional date, defaults to USD 222 | * 223 | * @param null|string $base 224 | * @param null|string $date 225 | * @param null|string $api override Provider setting 226 | * @param null|bool $https override https setting 227 | * @param null|bool $useCache override cache setting 228 | * @param null|int $cacheMin override cache setting 229 | * @param null|bool $runastest for testing, uses local test data. 230 | * 231 | * @return array 232 | */ 233 | public static function rates($base = null, $date = null, $api = null, $https = null, 234 | $useCache = null, $cacheMin = null, $runastest = false) : array 235 | { 236 | $rates = new self($api, $https, $useCache, $cacheMin, $runastest); 237 | return $rates->getRateResults($base, $date); 238 | } 239 | 240 | 241 | /** 242 | * Get the provider model instance 243 | * 244 | * @return Providers\CurrencyLayer|Providers\EuropeanCentralBank|Providers\Fixer|Providers\OpenExchange 245 | */ 246 | public function provider() { 247 | return $this->provider; 248 | } 249 | 250 | /** 251 | * Money formatter 252 | * 253 | * @param int $amount 254 | * @param string $currency 255 | * 256 | * @return Money 257 | */ 258 | public static function money($amount = 0, $currency = 'USD') : Money 259 | { 260 | return new Money($amount, $currency); 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /src/CurrencyProvider.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 8/18/2018 5 | * Time: 10:29 AM 6 | */ 7 | 8 | namespace danielme85\CConverter; 9 | 10 | use danielme85\CConverter\Providers\EuropeanCentralBank; 11 | use danielme85\CConverter\Providers\Fixer; 12 | use danielme85\CConverter\Providers\OpenExchange; 13 | use danielme85\CConverter\Providers\CurrencyLayer; 14 | 15 | class CurrencyProvider 16 | { 17 | 18 | /** 19 | * @param string $apiSource 'eurocentralbank'|'openexchange'|'currencylayer'|'fixer' 20 | * @param array $settings 21 | * @return CurrencyLayer|EuropeanCentralBank|Fixer|OpenExchange 22 | * @throws \Exception 23 | */ 24 | public static function getProvider($apiSource, $settings) 25 | { 26 | if ($apiSource === 'eurocentralbank') { 27 | return new EuropeanCentralBank($settings); 28 | } 29 | else if ($apiSource === 'openexchange') { 30 | return new OpenExchange($settings); 31 | } 32 | else if ($apiSource === 'currencylayer') { 33 | return new CurrencyLayer($settings); 34 | } 35 | else if ($apiSource === 'fixer') { 36 | return new Fixer($settings); 37 | } 38 | else { 39 | throw new \Exception("No suitable data provider found for Currency Converter", 500); 40 | } 41 | } 42 | 43 | 44 | } -------------------------------------------------------------------------------- /src/Providers/BaseProvider.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 8/18/2018 5 | * Time: 11:24 AM 6 | */ 7 | 8 | namespace danielme85\CConverter\Providers; 9 | 10 | use GuzzleHttp\Client; 11 | 12 | class BaseProvider 13 | { 14 | public $api; 15 | public $logEnabled; 16 | 17 | protected $date; 18 | protected $currency; 19 | protected $baseRates; 20 | 21 | protected $runastest; 22 | protected $settings; 23 | 24 | protected $url; 25 | 26 | /** 27 | * BaseProvider constructor. 28 | * 29 | * @param array $settings 30 | */ 31 | public function __construct($settings) 32 | { 33 | $this->settings = $settings; 34 | $this->api = $settings['api-source']; 35 | $this->logEnabled = $settings['enable-log']; 36 | $this->runastest = $settings['runastest']; 37 | } 38 | 39 | /** 40 | * Connect to the providers API 41 | * 42 | * @param string $url 43 | * @param array $headers 44 | * 45 | * @return string 46 | */ 47 | protected function connect($url, $headers = null) 48 | { 49 | if (!empty($headers)) { 50 | $client = new Client(['headers' => $headers]); 51 | } 52 | else { 53 | $client = new Client(); 54 | } 55 | $request = $client->get($url); 56 | $response = $request->getBody()->getContents(); 57 | 58 | return $response; 59 | } 60 | 61 | /** 62 | * Set rates 63 | * 64 | * @param Rates $rates 65 | * 66 | * @return bool 67 | */ 68 | protected function setBaseRates(Rates $rates) : bool 69 | { 70 | if (!empty($rates)) { 71 | if (isset($rates->base) and isset($rates->date)) { 72 | $this->baseRates[$rates->base][$rates->date] = $rates; 73 | 74 | if (!empty($this->baseRates[$rates->base][$rates->date])) { 75 | return true; 76 | } 77 | } 78 | } 79 | 80 | return false; 81 | } 82 | 83 | /** 84 | * Get rates 85 | * 86 | * @param string $currency 87 | * @param string $date 88 | * 89 | * @return Rates|null 90 | */ 91 | protected function getBaseRates(string $currency, string $date) 92 | { 93 | $this->currency = $currency; 94 | $this->date = $date; 95 | 96 | if (isset($this->baseRates[strtoupper($currency)][$date])) { 97 | 98 | return $this->baseRates[strtoupper($currency)][$date]; 99 | } 100 | 101 | return null; 102 | } 103 | 104 | } -------------------------------------------------------------------------------- /src/Providers/CurrencyLayer.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 8/18/2018 5 | * Time: 10:53 AM 6 | */ 7 | 8 | namespace danielme85\CConverter\Providers; 9 | 10 | class CurrencyLayer extends BaseProvider implements ProviderInterface 11 | { 12 | 13 | /** 14 | * Get Currency Rates 15 | * 16 | * @param string $currency 17 | * @param string|null $date 18 | * 19 | * @return Rates 20 | */ 21 | public function rates(string $currency, string $date = null) : Rates 22 | { 23 | $rates = $this->getBaseRates($currency, $date); 24 | if (empty($rates)) { 25 | $rates = $this->convert($this->download($date)); 26 | 27 | if ($currency !== 'USD') { 28 | $rates = $rates->convertBaseRateToCurrency($currency); 29 | $this->setBaseRates($rates); 30 | } 31 | else { 32 | $this->setBaseRates($rates); 33 | } 34 | } 35 | 36 | return $rates; 37 | } 38 | 39 | /** 40 | * Get data from jsonRates 41 | * 42 | * @return array 43 | */ 44 | private function download($fromDate = null, $toDate = null) { 45 | //use test data if running as test 46 | if ($this->runastest) { 47 | $response = file_get_contents(dirname(__FILE__). '/../../tests/currencyLayerTestData.json'); 48 | } 49 | else { 50 | $base = 'USD'; 51 | 52 | if ($this->settings['use-ssl']) { 53 | $url = 'https'; 54 | } else { 55 | $url = 'http'; 56 | } 57 | 58 | if (!empty($fromDate) and !empty($toDate)) { 59 | $url .= '://apilayer.net/api/timeframe?access_key='.$this->settings['currencylayer-access-key'].'&source='.$base.'&start_date='.$fromDate.'&end_date='.$toDate; 60 | } 61 | else if (!empty($fromDate)) { 62 | $url .= '://apilayer.net/api/historical?access_key=' . $this->settings['currencylayer-access-key'] . '&date=' . $fromDate . '&source=' . $base; 63 | 64 | } else { 65 | $url .= '://apilayer.net/api/live?access_key=' . $this->settings['currencylayer-access-key'] . '&source=' . $base; 66 | } 67 | $this->url = $url; 68 | $response = $this->connect($url); 69 | } 70 | 71 | return $response; 72 | } 73 | 74 | 75 | /** 76 | * Convert data from jsonRates to standardized format. 77 | * 78 | * @param array $data 79 | * @return Rates 80 | */ 81 | private function convert($input): Rates 82 | { 83 | $rates = new Rates(); 84 | $rates->timestamp = time(); 85 | $rates->date = $this->date; 86 | $rates->base = 'USD'; 87 | $rates->rates = []; 88 | $this->url = $this->url; 89 | 90 | $data = json_decode($input, true); 91 | 92 | if (!empty($data)) { 93 | if (isset($data['success'])) { 94 | if ($data['success']) { 95 | $rates->extra['cl_timestamp'] = $data['timestamp'] ?? null; 96 | $newrates = []; 97 | if (isset($data['quotes']) and is_array($data['quotes'])) { 98 | foreach ($data['quotes'] as $key => $row) { 99 | if ($key === "$rates->base$rates->base") { 100 | $key = $rates->base; 101 | } else { 102 | $key = str_replace($rates->base, '', $key); 103 | } 104 | $newrates[$key] = round($row, 5); 105 | } 106 | } 107 | } 108 | } 109 | if (isset($data['error'])) { 110 | $rates->extra['cl_error'] = $data['error'] ?? null; 111 | } 112 | } 113 | else { 114 | $rates->error = "No data in response from Currency Layer."; 115 | } 116 | 117 | if (!empty($newrates)) { 118 | $rates->rates = $newrates; 119 | } 120 | 121 | return $rates; 122 | } 123 | } -------------------------------------------------------------------------------- /src/Providers/EuropeanCentralBank.php: -------------------------------------------------------------------------------- 1 | getBaseRates($currency, $date); 27 | if (empty($rates)) { 28 | $rates = $this->convert($this->download($date)); 29 | if ($currency !== 'EUR') { 30 | //Set USD base rate 31 | $this->setBaseRates($rates->convertBaseRatesToUSD()); 32 | 33 | if ($currency !== 'USD') { 34 | $rates = $rates->convertBaseRateToCurrency($currency); 35 | $this->setBaseRates($rates); 36 | } 37 | } 38 | else { 39 | $this->setBaseRates($rates); 40 | } 41 | } 42 | 43 | return $rates; 44 | } 45 | 46 | /** 47 | * Download new data 48 | * 49 | * @param null|string $date 50 | * 51 | * @return mixed 52 | */ 53 | private function download($date = null) 54 | { 55 | //use test data if running as test 56 | if ($this->runastest) { 57 | $response = file_get_contents(dirname(__FILE__). '/../../tests/europeanCentralBankTestData.json'); 58 | } 59 | else { 60 | if ($this->settings['use-ssl']) { 61 | $url = 'https'; 62 | } else { 63 | $url = 'http'; 64 | } 65 | if (empty($date)) { 66 | $date = date('Y-m-d'); 67 | } 68 | $url .= "://sdw-wsrest.ecb.europa.eu/service/data/EXR/D..EUR.SP00.A?startPeriod=$date&endPeriod=$date&detail=dataonly"; 69 | 70 | $this->url = $url; 71 | 72 | $response = $this->connect($url, [ 73 | 'Accept' => 'application/vnd.sdmx.data+json;version=1.0.0-wd', 74 | 'Accept-Encoding' => 'gzip' 75 | ]); 76 | } 77 | 78 | return $response; 79 | } 80 | 81 | 82 | /** 83 | * Convert data from fixer.io to standardized format. 84 | * @param $input 85 | * 86 | * @return Rates 87 | */ 88 | private function convert($input) : Rates 89 | { 90 | $rates = new Rates(); 91 | $rates->timestamp = time(); 92 | $rates->date = $this->date; 93 | $rates->base = 'EUR'; 94 | $rates->rates = []; 95 | $rates->url = $this->url; 96 | 97 | if (!empty($input)) { 98 | $data = json_decode($input, true); 99 | if (!empty($data)) { 100 | $series = end($data['dataSets']) ?? null; 101 | $structure = $data['structure']['dimensions']['series'] ?? null; 102 | 103 | $rates->extra['european_central_bank_valid_from'] = $series['validFrom'] ?? null; 104 | 105 | $newrates = []; 106 | 107 | if (!empty($structure)) { 108 | foreach ($structure as $struc) { 109 | if ($struc['id'] === 'CURRENCY') { 110 | if (!empty($struc['values'])) { 111 | foreach ($struc['values'] as $label) { 112 | $labels[] = $label['id']; 113 | } 114 | } 115 | } 116 | } 117 | } 118 | 119 | if (!empty($series['series'])) { 120 | foreach ($series['series'] as $row) { 121 | $avg = 0; 122 | $counter = 0; 123 | foreach ($row as $subrow) { 124 | if (!empty($subrow)) { 125 | foreach ($subrow as $value) { 126 | $avg += $value[0]; 127 | $counter++; 128 | } 129 | } 130 | } 131 | $newrates[] = $avg / $counter; 132 | } 133 | } 134 | 135 | if (!empty($labels) and !empty($newrates)) { 136 | foreach ($labels as $i => $label) { 137 | $rates->rates[$label] = $newrates[$i]; 138 | } 139 | //add 1:1 conversion rate from base for testing 140 | $rates->rates['EUR'] = 1; 141 | } 142 | } 143 | } 144 | else { 145 | $rates->error = "No data in response from the European Central Bank."; 146 | } 147 | 148 | return $rates; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/Providers/Fixer.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 8/18/2018 5 | * Time: 10:24 AM 6 | */ 7 | 8 | namespace danielme85\CConverter\Providers; 9 | 10 | class Fixer extends BaseProvider implements ProviderInterface 11 | { 12 | public $name = "Fixer.io"; 13 | 14 | /** 15 | * Get Currency Rates 16 | * 17 | * @param string $currency 18 | * @param string|null $date 19 | * 20 | * @return Rates 21 | */ 22 | public function rates(string $currency, string $date = null) : Rates 23 | { 24 | $rates = $this->getBaseRates($currency, $date); 25 | if (empty($rates)) { 26 | if ($this->settings['fixer-use-real-base']) { 27 | $base = strtoupper($currency); 28 | } 29 | else { 30 | $base = 'EUR'; 31 | } 32 | $rates = $this->convert($this->download($base, $date)); 33 | if ($currency !== 'EUR') { 34 | //Set USD base rate 35 | $this->setBaseRates($rates->convertBaseRatesToUSD()); 36 | 37 | if ($currency !== 'USD') { 38 | $rates = $rates->convertBaseRateToCurrency($currency); 39 | $this->setBaseRates($rates); 40 | } 41 | } 42 | else { 43 | $this->setBaseRates($rates); 44 | } 45 | } 46 | 47 | return $rates; 48 | } 49 | 50 | 51 | /** 52 | * 53 | * @param string $currency 54 | * @param string|null $date 55 | * 56 | * @return array 57 | */ 58 | public function download(string $currency, string $date = null) { 59 | //use test data if running as test 60 | if ($this->runastest) { 61 | $response = file_get_contents(dirname(__FILE__). '/../../tests/fixerTestData.json'); 62 | } 63 | else { 64 | if ($this->settings['use-ssl']) { 65 | $url = 'https'; 66 | } else { 67 | $url = 'http'; 68 | } 69 | if (!empty($date)) { 70 | $url .= "://data.fixer.io/api/$date?access_key=".$this->settings['fixer-access-key']."&base=$currency"; 71 | } else { 72 | $url .= "://data.fixer.io/api/latest?access_key=".$this->settings['fixer-access-key']."&base=$currency"; 73 | } 74 | $this->url = $url; 75 | $response = $this->connect($url); 76 | } 77 | 78 | return $response; 79 | } 80 | 81 | 82 | /** 83 | * Convert data from fixer.io to standardized format. 84 | * 85 | * @param string $input 86 | * @return Rates 87 | */ 88 | private function convert($input) : Rates 89 | { 90 | $rates = new Rates(); 91 | $rates->timestamp = time(); 92 | $rates->date = $this->date; 93 | $rates->base = 'EUR'; 94 | $rates->rates = []; 95 | $rates->url = $this->url; 96 | 97 | $data = json_decode($input, true); 98 | 99 | if (!empty($data)) { 100 | if (!empty($data['rates'])) { 101 | $rates->extra['fixer_date'] = $data['date'] ?? null; 102 | foreach ($data['rates'] as $key => $row) { 103 | $rates->rates[$key] = $row; 104 | } 105 | //add 1:1 conversion rate from base for testing 106 | $rates->rates[$data['base']] = 1; 107 | } 108 | } 109 | else { 110 | $rates->error = "No data in response from Fixer.io"; 111 | } 112 | 113 | return $rates; 114 | } 115 | } -------------------------------------------------------------------------------- /src/Providers/OpenExchange.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 8/18/2018 5 | * Time: 10:24 AM 6 | */ 7 | 8 | namespace danielme85\CConverter\Providers; 9 | 10 | use Illuminate\Support\Facades\Log; 11 | 12 | class OpenExchange extends BaseProvider implements ProviderInterface 13 | { 14 | public $name = 'Open Exchange Rates'; 15 | 16 | /** 17 | * Get the rates from this provider. 18 | * 19 | * @param string $currency 20 | * @param string $date 21 | * 22 | * @return Rates 23 | */ 24 | public function rates(string $currency, string $date): Rates 25 | { 26 | $rates = $this->getBaseRates($currency, $date); 27 | if (empty($rates)) { 28 | if ($this->settings['openex-use-real-base']) { 29 | $rates = $this->convert($this->download($currency, $date)); 30 | } else { 31 | $rates = $this->convert($this->download('USD', $date)); 32 | if ($currency !== 'USD') { 33 | $rates = $rates->convertBaseRateToCurrency($currency); 34 | } 35 | } 36 | $this->setBaseRates($rates); 37 | } 38 | 39 | 40 | return $rates; 41 | } 42 | 43 | /** 44 | * Get data from openExchange 45 | * 46 | * @param string $currency 47 | * @param string $date 48 | * 49 | * @return array 50 | */ 51 | private function download($currency, $date) 52 | { 53 | //use test data if running as test 54 | if ($this->runastest) { 55 | $results = file_get_contents(dirname(__FILE__) . '/../../tests/openExchangeTestData.json'); 56 | } 57 | else { 58 | if ($this->settings['use-ssl']) { 59 | $url = 'https'; 60 | } else { 61 | $url = 'http'; 62 | } 63 | 64 | if ($date === date('Y-m-d')) { 65 | $url .= '://openexchangerates.org/api/latest.json?app_id=' . $this->settings['openex-app-id'] . '&base=' . $currency; 66 | } else { 67 | $url .= '://openexchangerates.org/api/time-series.json?app_id=' . $this->settings['openex-app-id'] . '&start=' . $date . '&end=' . $date . '&base=' . $currency; 68 | } 69 | $this->url = $url; 70 | $results = $this->connect($url); 71 | } 72 | 73 | return $results; 74 | } 75 | 76 | /** 77 | * Convert data from from OpenExchangeRate to standardized format. 78 | * @param $data 79 | * 80 | * @return Rates 81 | */ 82 | protected function convert($input) : Rates 83 | { 84 | $rates = new Rates(); 85 | $rates->timestamp = time(); 86 | $rates->date = $this->date; 87 | $rates->base = 'USD'; 88 | $rates->rates = []; 89 | $rates->url = $this->url; 90 | 91 | if ($this->date !== date('Y-m-d')) { 92 | $date = $this->date; 93 | } else { 94 | $date = null; 95 | } 96 | 97 | $data = json_decode($input, true); 98 | if (!empty($data)) { 99 | if (!empty($date)) { 100 | if (isset($data['rates'][$date]) and is_array($data['rates'][$date])) { 101 | foreach ($data['rates'][$date] as $key => $row) { 102 | $rates->rates[$key] = $row; 103 | } 104 | } else { 105 | Log::warning('No results returned from OpenExchange.'); 106 | } 107 | } else { 108 | if (isset($data['rates']) and is_array($data['rates'])) { 109 | $rates->rates = $data['rates']; 110 | } else { 111 | Log::warning('No results returned from OpenExchange.'); 112 | } 113 | } 114 | } 115 | else { 116 | $rates->error = "No data in response from OpenExchange"; 117 | } 118 | 119 | return $rates; 120 | } 121 | 122 | } -------------------------------------------------------------------------------- /src/Providers/ProviderInterface.php: -------------------------------------------------------------------------------- 1 | 4 | * Date: 8/18/2018 5 | * Time: 11:33 AM 6 | */ 7 | 8 | namespace danielme85\CConverter\Providers; 9 | 10 | 11 | interface ProviderInterface 12 | { 13 | public function rates(string $currency, string $date); 14 | } -------------------------------------------------------------------------------- /src/Providers/Rates.php: -------------------------------------------------------------------------------- 1 | rates)) { 30 | if ($this->base !== $currency) { 31 | if (!empty($this->rates[$currency])) { 32 | $usdrate = $this->rates[$currency]; 33 | foreach ($this->rates as $key => $rate) { 34 | $newrates[$key] = $rate * (1 / $usdrate); 35 | } 36 | } 37 | } 38 | } 39 | if (!empty($newrates)) { 40 | $this->rates = $newrates; 41 | $this->base = $currency; 42 | } 43 | 44 | return $this; 45 | } 46 | 47 | /** 48 | * Convert rates to USD 49 | * 50 | * @return Rates 51 | */ 52 | public function convertBaseRatesToUSD() : Rates 53 | { 54 | if (!empty($this->rates)) { 55 | if ($this->base !== 'USD') { 56 | if (!empty($this->rates['USD'])) { 57 | $usdrate = $this->rates['USD']; 58 | foreach ($this->rates as $key => $rate) { 59 | $newrates[$key] = $rate * (1 / $usdrate); 60 | } 61 | } 62 | } 63 | } 64 | if (!empty($newrates)) { 65 | $this->rates = $newrates; 66 | $this->base = 'USD'; 67 | } 68 | 69 | return $this; 70 | } 71 | 72 | public function toArray() : array 73 | { 74 | return json_decode(json_encode($this), true); 75 | } 76 | 77 | } -------------------------------------------------------------------------------- /tests/CurrencyConvertTest.php: -------------------------------------------------------------------------------- 1 | load(); 29 | } 30 | 31 | $hash1 = getenv('HASH1') ?: env('HASH1') ?: ''; 32 | $hash2 = getenv('HASH2') ?: env('HASH2') ?: ''; 33 | $hash3 = getenv('HASH3') ?: env('HASH3') ?: ''; 34 | $app['config']->set('currencyConverter.openex-app-id', $hash1); 35 | $app['config']->set('currencyConverter.currencylayer-access-key', $hash2); 36 | $app['config']->set('currencyConverter.fixer-access-key', $hash3); 37 | } 38 | 39 | /** 40 | * Test of default settings and init 41 | * @group basics 42 | * 43 | * @return void 44 | */ 45 | public function testDefaultApi() { 46 | $currency = new Currency(null, null, false, null, true); 47 | 48 | $rates = $currency->getRateResults(); 49 | $this->assertNotEmpty($rates); 50 | $this->assertEquals(1, $rates['USD']); 51 | 52 | $this->assertEquals(8.47, $currency->convert('USD', 'NOK', 1)); 53 | $this->assertEquals(846.94, $currency->convert('USD', 'NOK', 100)); 54 | 55 | $this->assertEquals(0.88, $currency->convert('USD', 'EUR', 1)); 56 | $this->assertEquals(87.57, $currency->convert('USD', 'EUR', 100)); 57 | 58 | $this->assertEquals(10, $currency->convert('USD', 'USD', 10)); 59 | $this->assertEquals(10, $currency->convert('EUR', 'EUR', 10)); 60 | $this->assertEquals(10, $currency->convert('NOK', 'NOK', 10)); 61 | } 62 | 63 | /** 64 | * Test the static function "shortcuts" 65 | * 66 | * @group basics 67 | * 68 | * @return void 69 | */ 70 | public function testStaticShortCalls() { 71 | 72 | $usrates = Currency::rates(null, null, null, null, true, 5, true); 73 | $this->assertEquals(1, $usrates['USD']); 74 | 75 | $eurorates = Currency::rates('EUR', null, null, null, true, 5, true); 76 | $this->assertEquals(1, $eurorates['EUR']); 77 | 78 | $this->assertEquals(1, Currency::conv('USD', 'USD', 1, null, null, null, null, true, 5, true)); 79 | 80 | } 81 | 82 | /** 83 | * Test to see if the Currency object can be created with The European Central Bank 84 | * @group eurobank 85 | * 86 | * @return void 87 | */ 88 | public function testEuroBank() 89 | { 90 | $currency = new Currency('eurocentralbank', null, false, null, true); 91 | $this->assertNotEmpty($currency->getRateResults()); 92 | $this->assertEquals(1, $currency->convert('USD', 'USD', 1)); 93 | $this->assertEquals(1, $currency->convert('EUR', 'EUR', 1)); 94 | $this->assertEquals(1, $currency->convert('NOK', 'NOK', 1)); 95 | } 96 | 97 | /** 98 | * Test to see if the Currency object can be created with fixer. 99 | * @group fixer 100 | * 101 | * @return void 102 | */ 103 | public function testFixer() 104 | { 105 | $currency = new Currency('fixer', null, false, null, true); 106 | $this->assertNotEmpty($currency->getRateResults()); 107 | $this->assertEquals(1, $currency->convert('USD', 'USD', 1)); 108 | $this->assertEquals(1, $currency->convert('EUR', 'EUR', 1)); 109 | $this->assertEquals(1, $currency->convert('NOK', 'NOK', 1)); 110 | 111 | //Live test 112 | $currency = new Currency('fixer', false); 113 | $this->assertNotEmpty($currency->getRateResults()); 114 | $this->assertNotEmpty($currency->getRateResults('USD', '2019-01-01')); 115 | $this->assertEquals(1, $currency->convert('USD', 'USD', 1)); 116 | $this->assertEquals(1, $currency->convert('EUR', 'EUR', 1)); 117 | $this->assertEquals(1, $currency->convert('NOK', 'NOK', 1)); 118 | 119 | 120 | $this->assertNotEmpty(Currency::rates('USD', '2019-01-01', 'fixer', false, true)); 121 | $this->assertEquals(1, Currency::conv('USD', 'USD', 1, null, '2019-01-01', 'fixer', false, true)); 122 | $this->assertEquals(1, Currency::conv('EUR', 'EUR', 1, null, '2019-01-01', 'fixer', false, true)); 123 | 124 | } 125 | 126 | /** 127 | * Test to see if the Currency object can be created with CurrencyLayer. 128 | * @group currencylayer 129 | * 130 | * @return void 131 | */ 132 | public function testCurrencyLayer() 133 | { 134 | $currency = new Currency('currencylayer', null, false, null, true); 135 | $this->assertNotEmpty($currency->getRateResults()); 136 | $this->assertEquals(1, $currency->convert('USD', 'USD', 1)); 137 | $this->assertEquals(1, $currency->convert('EUR', 'EUR', 1)); 138 | $this->assertEquals(1, $currency->convert('NOK', 'NOK', 1)); 139 | 140 | //Live test 141 | $currency = new Currency('currencylayer', false); 142 | $this->assertNotEmpty($currency->getRateResults()); 143 | $this->assertNotEmpty($currency->getRateResults('USD', '2019-01-01')); 144 | $this->assertEquals(1, $currency->convert('USD', 'USD', 1)); 145 | $this->assertEquals(1, $currency->convert('EUR', 'EUR', 1)); 146 | $this->assertEquals(1, $currency->convert('NOK', 'NOK', 1)); 147 | 148 | $this->assertNotEmpty(Currency::rates('USD', '2019-01-01', 'currencylayer')); 149 | $this->assertEquals(1, Currency::conv('USD', 'USD', 1, null, '2019-01-01', 'currencylayer', false, true)); 150 | $this->assertEquals(1, Currency::conv('EUR', 'EUR', 1, null, '2019-01-01', 'currencylayer', false, true)); 151 | 152 | 153 | } 154 | 155 | /** 156 | * Test to see if the Currency object can be created with OpenExchange. 157 | * @group openexchange 158 | * 159 | * @return void 160 | */ 161 | public function testOpenExchange() 162 | { 163 | $currency = new Currency('openexchange', null, false, null, true); 164 | $this->assertNotEmpty($currency->getRateResults()); 165 | $this->assertEquals(1, $currency->convert('USD', 'USD', 1)); 166 | $this->assertEquals(1, $currency->convert('EUR', 'EUR', 1)); 167 | 168 | //Live test 169 | $currency = new Currency('openexchange', false); 170 | $this->assertNotEmpty($currency->getRateResults()); 171 | $this->assertEquals(1, $currency->convert('USD', 'USD', 1)); 172 | $this->assertEquals(1, $currency->convert('EUR', 'EUR', 1)); 173 | $this->assertEquals(1, $currency->convert('NOK', 'NOK', 1)); 174 | 175 | $this->assertEquals(1, Currency::conv('USD', 'USD', 1, null, null, 'openexchange', false, true)); 176 | $this->assertEquals(1, Currency::conv('EUR', 'EUR', 1, null, null, 'openexchange', false, true)); 177 | 178 | } 179 | 180 | /** 181 | * Test the money formatter. 182 | * @group money 183 | * 184 | * @return void 185 | */ 186 | public function testMoneyFormat() { 187 | $currency = new Currency(null, null, false, null, true); 188 | $this->assertEquals('$10.00', $currency->convert('USD','USD', 10, 'money')); 189 | $this->assertEquals('$199.99', Currency::money(199.99, 'USD')); 190 | $this->assertEquals('kr 8,47', $currency->convert('USD','NOK', 1, 'money')); 191 | } 192 | 193 | /** 194 | * Test the Rate Model 195 | * @group ratearray 196 | * 197 | * @return void 198 | */ 199 | public function testGetRatesArray() { 200 | $currency = new Currency(null, null, false, null, true); 201 | $array = $currency->getRates(); 202 | $this->assertArrayHasKey('base', $array); 203 | $this->assertArrayHasKey('rates', $array); 204 | $this->assertNotEmpty($array['rates']); 205 | } 206 | 207 | /** 208 | * Test the Rate Model 209 | * @group ratemodel 210 | * 211 | * @return void 212 | */ 213 | public function testGetRateModel() { 214 | $currency = new Currency(null, null, false, null, true); 215 | $model = $currency->getRateModel(); 216 | $this->assertObjectHasAttribute('base', $model); 217 | $this->assertObjectHasAttribute('rates', $model); 218 | 219 | } 220 | } -------------------------------------------------------------------------------- /tests/currencyLayerTestData.json: -------------------------------------------------------------------------------- 1 | {"success":true,"terms":"https:\/\/currencylayer.com\/terms","privacy":"https:\/\/currencylayer.com\/privacy","timestamp":1517330889,"source":"USD","quotes":{"USDAED":3.671698,"USDAFN":69.260002,"USDALL":107.249963,"USDAMD":480.130005,"USDANG":1.779745,"USDAOA":204.800995,"USDARS":19.594999,"USDAUD":1.237803,"USDAWG":1.78,"USDAZN":1.699603,"USDBAM":1.581196,"USDBBD":2,"USDBDT":82.870003,"USDBGN":1.574604,"USDBHD":0.376699,"USDBIF":1750.97998,"USDBMD":1,"USDBND":1.325701,"USDBOB":6.859606,"USDBRL":3.186297,"USDBSD":1,"USDBTC":9.6e-5,"USDBTN":63.549999,"USDBWP":9.619598,"USDBYN":2.019915,"USDBYR":19600,"USDBZD":1.997804,"USDCAD":1.23423,"USDCDF":1565.494877,"USDCHF":0.93542,"USDCLF":0.02241,"USDCLP":607.799988,"USDCNY":6.319799,"USDCOP":2845.5,"USDCRC":564.99975,"USDCUC":1,"USDCUP":26.5,"USDCVE":88.999927,"USDCZK":20.421699,"USDDJF":176.830002,"USDDKK":6.00614,"USDDOP":48.700001,"USDDZD":113.060997,"USDEGP":17.629999,"USDERN":14.9897,"USDETB":27.200001,"USDEUR":0.8069,"USDFJD":1.986007,"USDFKP":0.707898,"USDGBP":0.70854,"USDGEL":2.485001,"USDGGP":0.708565,"USDGHS":4.488504,"USDGIP":0.708202,"USDGMD":48.209999,"USDGNF":9003.999833,"USDGTQ":7.335982,"USDGYD":204.669998,"USDHKD":7.819299,"USDHNL":23.499357,"USDHRK":5.982702,"USDHTG":63.069852,"USDHUF":250.869995,"USDIDR":13428,"USDILS":3.415496,"USDIMP":0.708565,"USDINR":63.7854,"USDIQD":1184,"USDIRR":36904.999881,"USDISK":100.501776,"USDJEP":0.708565,"USDJMD":123.690002,"USDJOD":0.707495,"USDJPY":108.872002,"USDKES":102.150002,"USDKGS":68.364998,"USDKHR":4000.000349,"USDKMF":395.899994,"USDKPW":900.000221,"USDKRW":1072.02002,"USDKWD":0.299299,"USDKYD":0.819642,"USDKZT":321.609985,"USDLAK":8278.999854,"USDLBP":1510.999849,"USDLKR":153.899994,"USDLRD":128.929993,"USDLSL":11.970252,"USDLTL":3.048697,"USDLVL":0.62055,"USDLYD":1.328301,"USDMAD":9.162006,"USDMDL":16.808979,"USDMGA":3205.000057,"USDMKD":49.419998,"USDMMK":1327.999703,"USDMNT":2411.999857,"USDMOP":8.0475,"USDMRO":350.999966,"USDMUR":32.150002,"USDMVR":15.570552,"USDMWK":713.450012,"USDMXN":18.695299,"USDMYR":3.899499,"USDMZN":59.999869,"USDNAD":11.950414,"USDNGN":357.999824,"USDNIO":30.950001,"USDNOK":7.71882,"USDNPR":101.804001,"USDNZD":1.363298,"USDOMR":0.384499,"USDPAB":1,"USDPEN":3.216502,"USDPGK":3.14402,"USDPHP":51.490002,"USDPKR":110.470001,"USDPLN":3.355599,"USDPYG":5614.799805,"USDQAR":3.6398,"USDRON":3.751703,"USDRSD":95.710999,"USDRUB":56.371201,"USDRWF":835.75,"USDSAR":3.750172,"USDSBD":7.749402,"USDSCR":13.401592,"USDSDG":18.612201,"USDSEK":7.88806,"USDSGD":1.31164,"USDSHP":0.708205,"USDSLL":7680.000027,"USDSOS":563.000098,"USDSRD":7.420055,"USDSTD":19775.599609,"USDSVC":8.750086,"USDSYP":514.97998,"USDSZL":11.962052,"USDTHB":31.429733,"USDTJS":8.825499,"USDTMT":3.4,"USDTND":2.387297,"USDTOP":2.231102,"USDTRY":3.783502,"USDTTD":6.6295,"USDTWD":29.268999,"USDTZS":2246.999662,"USDUAH":27.919797,"USDUGX":3614.000248,"USDUSD":1,"USDUYU":28.330091,"USDUZS":8164.999658,"USDVEF":9.97503,"USDVND":22700,"USDVUV":102.519997,"USDWST":2.505702,"USDXAF":529.099976,"USDXAG":0.058238,"USDXAU":0.000746,"USDXCD":2.703065,"USDXDR":0.687212,"USDXOF":526.000088,"USDXPF":96.569725,"USDYER":249.899994,"USDZAR":11.954101,"USDZMK":9001.197519,"USDZMW":9.680099,"USDZWL":322.355011}} -------------------------------------------------------------------------------- /tests/europeanCentralBankTestData.json: -------------------------------------------------------------------------------- 1 | {"header":{"id":"125c3859-9bee-44d9-b791-0bb7fca8d56f","test":false,"prepared":"2018-08-20T17:01:01.549+02:00","sender":{"id":"ECB"}},"dataSets":[{"action":"Replace","validFrom":"2018-08-20T17:01:01.549+02:00","series":{"0:0:0:0:0":{"observations":{"0":[34.103]}},"0:1:0:0:0":{"observations":{"0":[1.5631]}},"0:2:0:0:0":{"observations":{"0":[1.9558]}},"0:3:0:0:0":{"observations":{"0":[4.4818]}},"0:4:0:0:0":{"observations":{"0":[1.4927]}},"0:5:0:0:0":{"observations":{"0":[1.1366]}},"0:6:0:0:0":{"observations":{"0":[7.8351]}},"0:7:0:0:0":{"observations":{"0":[25.706]}},"0:8:0:0:0":{"observations":{"0":[7.4588]}},"0:9:0:0:0":{"observations":{"0":[135.7385]}},"0:10:0:0:0":{"observations":{"0":[0.89478]}},"0:11:0:0:0":{"observations":{"0":[8.9645]}},"0:12:0:0:0":{"observations":{"0":[7.417]}},"0:13:0:0:0":{"observations":{"0":[323.53]}},"0:14:0:0:0":{"observations":{"0":[16661.78]}},"0:15:0:0:0":{"observations":{"0":[4.1814]}},"0:16:0:0:0":{"observations":{"0":[79.74]}},"0:17:0:0:0":{"observations":{"0":[123]}},"0:18:0:0:0":{"observations":{"0":[126.25]}},"0:19:0:0:0":{"observations":{"0":[1281.69]}},"0:20:0:0:0":{"observations":{"0":[10.8923]}},"0:21:0:0:0":{"observations":{"0":[21.63]}},"0:22:0:0:0":{"observations":{"0":[4.6828]}},"0:23:0:0:0":{"observations":{"0":[9.672]}},"0:24:0:0:0":{"observations":{"0":[1.7255]}},"0:25:0:0:0":{"observations":{"0":[60.953]}},"0:26:0:0:0":{"observations":{"0":[4.3037]}},"0:27:0:0:0":{"observations":{"0":[4.649]}},"0:28:0:0:0":{"observations":{"0":[76.7235]}},"0:29:0:0:0":{"observations":{"0":[10.4918]}},"0:30:0:0:0":{"observations":{"0":[1.5665]}},"0:31:0:0:0":{"observations":{"0":[37.726]}},"0:32:0:0:0":{"observations":{"0":[6.9863]}},"0:33:0:0:0":{"observations":{"0":[35.1508]}},"0:34:0:0:0":{"observations":{"0":[1.142]}},"0:35:0:0:0":{"observations":{"0":[16.6561]}}}}],"structure":{"links":[{"title":"Exchange Rates","rel":"dataflow","href":"https://sdw-wsrest.ecb.europa.eu:443/service/dataflow/ECB/EXR/1.0"}],"name":"Exchange Rates","dimensions":{"series":[{"id":"FREQ","name":"Frequency","values":[{"id":"D","name":"Daily"}]},{"id":"CURRENCY","name":"Currency","values":[{"id":"ARS","name":"Argentine peso"},{"id":"AUD","name":"Australian dollar"},{"id":"BGN","name":"Bulgarian lev"},{"id":"BRL","name":"Brazilian real"},{"id":"CAD","name":"Canadian dollar"},{"id":"CHF","name":"Swiss franc"},{"id":"CNY","name":"Chinese yuan renminbi"},{"id":"CZK","name":"Czech koruna"},{"id":"DKK","name":"Danish krone"},{"id":"DZD","name":"Algerian dinar"},{"id":"GBP","name":"UK pound sterling"},{"id":"HKD","name":"Hong Kong dollar"},{"id":"HRK","name":"Croatian kuna"},{"id":"HUF","name":"Hungarian forint"},{"id":"IDR","name":"Indonesian rupiah"},{"id":"ILS","name":"Israeli shekel"},{"id":"INR","name":"Indian rupee"},{"id":"ISK","name":"Iceland krona"},{"id":"JPY","name":"Japanese yen"},{"id":"KRW","name":"Korean won (Republic)"},{"id":"MAD","name":"Moroccan dirham"},{"id":"MXN","name":"Mexican peso"},{"id":"MYR","name":"Malaysian ringgit"},{"id":"NOK","name":"Norwegian krone"},{"id":"NZD","name":"New Zealand dollar"},{"id":"PHP","name":"Philippine piso"},{"id":"PLN","name":"Polish zloty"},{"id":"RON","name":"Romanian leu"},{"id":"RUB","name":"Russian rouble"},{"id":"SEK","name":"Swedish krona"},{"id":"SGD","name":"Singapore dollar"},{"id":"THB","name":"Thai baht"},{"id":"TRY","name":"Turkish lira"},{"id":"TWD","name":"New Taiwan dollar"},{"id":"USD","name":"US dollar"},{"id":"ZAR","name":"South African rand"}]},{"id":"CURRENCY_DENOM","name":"Currency denominator","values":[{"id":"EUR","name":"Euro"}]},{"id":"EXR_TYPE","name":"Exchange rate type","values":[{"id":"SP00","name":"Spot"}]},{"id":"EXR_SUFFIX","name":"Series variation - EXR context","values":[{"id":"A","name":"Average"}]}],"observation":[{"id":"TIME_PERIOD","name":"Time period or range","role":"time","values":[{"id":"2018-08-20","name":"2018-08-20","start":"2018-08-20T00:00:00.000+02:00","end":"2018-08-20T23:59:59.999+02:00"}]}]}}} -------------------------------------------------------------------------------- /tests/fixerTestData.json: -------------------------------------------------------------------------------- 1 | {"base":"USD","date":"2017-08-22","rates":{"AUD":1.2647,"BGN":1.6615,"BRL":3.152,"CAD":1.2578,"CHF":0.96542,"CNY":6.663,"CZK":22.159,"DKK":6.3187,"GBP":0.77914,"HKD":7.8268,"HRK":6.2905,"HUF":258.01,"IDR":13343,"ILS":3.6186,"INR":64.1,"JPY":109.36,"KRW":1134.2,"MXN":17.663,"MYR":4.281,"NOK":7.9027,"NZD":1.3733,"PHP":51.253,"PLN":3.6376,"RON":3.8967,"RUB":59.03,"SEK":8.1038,"SGD":1.362,"THB":33.24,"TRY":3.4976,"ZAR":13.203,"EUR":0.84955}} -------------------------------------------------------------------------------- /tests/openExchangeTestData.json: -------------------------------------------------------------------------------- 1 | {"disclaimer":"Usage subject to terms: https:\/\/openexchangerates.org\/terms","license":"https:\/\/openexchangerates.org\/license","timestamp":1517335200,"base":"USD","rates":{"AED":3.673014,"AFN":69.49662,"ALL":107.68,"AMD":480.695,"ANG":1.786635,"AOA":203.14,"ARS":19.632,"AUD":1.237647,"AWG":1.791246,"AZN":1.7,"BAM":1.5758,"BBD":2,"BDT":83.366931,"BGN":1.576844,"BHD":0.37694,"BIF":1770,"BMD":1,"BND":1.310883,"BOB":6.910011,"BRL":3.181285,"BSD":1,"BTC":9.7754291e-5,"BTN":63.664042,"BWP":9.573877,"BYN":1.9786,"BZD":2.011848,"CAD":1.232974,"CDF":1601,"CHF":0.934988,"CLF":0.0227,"CLP":607.8,"CNH":6.3323,"CNY":6.32365,"COP":2845.155,"CRC":568.78,"CUC":1,"CUP":25.5,"CVE":88.95,"CZK":20.4,"DJF":178.52,"DKK":5.99965,"DOP":48.52,"DZD":113.480231,"EGP":17.641,"ERN":14.995,"ETB":27.55,"EUR":0.806097,"FJD":2.006008,"FKP":0.707069,"GBP":0.707069,"GEL":2.494491,"GGP":0.707069,"GHS":4.495,"GIP":0.707069,"GMD":48.51,"GNF":9035.35,"GTQ":7.361629,"GYD":207.307607,"HKD":7.81996,"HNL":23.669803,"HRK":5.980258,"HTG":64.007985,"HUF":250.51275,"IDR":13408.25919,"ILS":3.418475,"IMP":0.707069,"INR":63.775,"IQD":1183.5,"IRR":36882.905082,"ISK":100.82,"JEP":0.707069,"JMD":124.50435,"JOD":0.709001,"JPY":108.829,"KES":102.39,"KGS":68.377499,"KHR":4015,"KMF":396.195578,"KPW":900,"KRW":1074.69,"KWD":0.299686,"KYD":0.834095,"KZT":321.99,"LAK":8295,"LBP":1513.9,"LKR":154.135901,"LRD":129.199915,"LSL":11.975,"LYD":1.33,"MAD":9.1638,"MDL":16.874883,"MGA":3220,"MKD":49.644091,"MMK":1331.7,"MNT":2416.156849,"MOP":8.059894,"MRO":355.5,"MRU":35.35,"MUR":32.3,"MVR":15.409873,"MWK":725.64,"MXN":18.7069,"MYR":3.900994,"MZN":60.003288,"NAD":11.9569,"NGN":360.5,"NIO":31.1,"NOK":7.714501,"NPR":101.88,"NZD":1.363643,"OMR":0.384969,"PAB":1,"PEN":3.216002,"PGK":3.1955,"PHP":51.428,"PKR":110.76,"PLN":3.35031,"PYG":5628.25,"QAR":3.641,"RON":3.748782,"RSD":95.7545,"RUB":56.3356,"RWF":845,"SAR":3.75065,"SBD":7.752483,"SCR":13.761762,"SDG":7.023224,"SEK":7.8839,"SGD":1.311794,"SHP":0.707069,"SLL":7693.52619,"SOS":582.75,"SRD":7.468,"SSP":130.2634,"STD":19785.561496,"STN":19.895,"SVC":8.757756,"SYP":515.00999,"SZL":11.975,"THB":31.421,"TJS":8.835135,"TMT":3.499986,"TND":2.402004,"TOP":2.213605,"TRY":3.781584,"TTD":6.736134,"TWD":29.255,"TZS":2249.95,"UAH":28.5586,"UGX":3628.35,"USD":1,"UYU":28.446067,"UZS":8182.5,"VEF":10.03215,"VND":22707.741548,"VUV":104.003926,"WST":2.490067,"XAF":528.765282,"XAG":0.05833293,"XAU":0.00074698,"XCD":2.70255,"XDR":0.687212,"XOF":528.765282,"XPD":0.00094565,"XPF":96.193016,"XPT":0.00100201,"YER":250.35,"ZAR":11.983473,"ZMW":9.759,"ZWL":322.355011}} -------------------------------------------------------------------------------- /tests/yahooTestData.json: -------------------------------------------------------------------------------- 1 | {"query":{"count":170,"created":"2017-08-22T14:12:32Z","lang":"en-US","results":{"rate":[{"id":"USDAED","Name":"USD\/AED","Rate":"3.6726","Date":"8\/22\/2017","Time":"2:25pm","Ask":"3.6731","Bid":"3.6726"},{"id":"USDAFN","Name":"USD\/AFN","Rate":"68.8000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"69.0000","Bid":"68.8000"},{"id":"USDALL","Name":"USD\/ALL","Rate":"112.3300","Date":"8\/22\/2017","Time":"1:30pm","Ask":"112.5800","Bid":"112.3300"},{"id":"USDAMD","Name":"USD\/AMD","Rate":"478.0500","Date":"8\/22\/2017","Time":"1:00pm","Ask":"479.0500","Bid":"478.0500"},{"id":"USDANG","Name":"USD\/ANG","Rate":"1.7800","Date":"8\/22\/2017","Time":"3:00pm","Ask":"1.8200","Bid":"1.7800"},{"id":"USDAOA","Name":"USD\/AOA","Rate":"165.0950","Date":"8\/22\/2017","Time":"0:00am","Ask":"166.7460","Bid":"165.0950"},{"id":"USDARS","Name":"USD\/ARS","Rate":"17.2150","Date":"8\/22\/2017","Time":"3:10pm","Ask":"17.2200","Bid":"17.2150"},{"id":"USDAUD","Name":"USD\/AUD","Rate":"1.2619","Date":"8\/22\/2017","Time":"3:12pm","Ask":"1.2629","Bid":"1.2619"},{"id":"USDAWG","Name":"USD\/AWG","Rate":"1.7800","Date":"8\/22\/2017","Time":"2:25pm","Ask":"1.8000","Bid":"1.7800"},{"id":"USDAZN","Name":"USD\/AZN","Rate":"1.7003","Date":"8\/22\/2017","Time":"7:00am","Ask":"1.7013","Bid":"1.7003"},{"id":"USDBAM","Name":"USD\/BAM","Rate":"1.6664","Date":"8\/22\/2017","Time":"3:10pm","Ask":"1.6689","Bid":"1.6664"},{"id":"USDBBD","Name":"USD\/BBD","Rate":"2.0000","Date":"8\/22\/2017","Time":"3:00pm","Ask":"N\/A","Bid":"2.0000"},{"id":"USDBDT","Name":"USD\/BDT","Rate":"81.2100","Date":"8\/22\/2017","Time":"2:25pm","Ask":"81.4600","Bid":"81.2100"},{"id":"USDBGN","Name":"USD\/BGN","Rate":"1.6630","Date":"8\/21\/2017","Time":"3:15pm","Ask":"N\/A","Bid":"1.6630"},{"id":"USDBHD","Name":"USD\/BHD","Rate":"0.3771","Date":"8\/22\/2017","Time":"2:25pm","Ask":"0.3773","Bid":"0.3771"},{"id":"USDBIF","Name":"USD\/BIF","Rate":"1727.3101","Date":"8\/22\/2017","Time":"2:25pm","Ask":"1747.3101","Bid":"1727.3101"},{"id":"USDBMD","Name":"USD\/BMD","Rate":"1.0000","Date":"8\/22\/2017","Time":"3:00pm","Ask":"N\/A","Bid":"1.0000"},{"id":"USDBND","Name":"USD\/BND","Rate":"1.3610","Date":"8\/22\/2017","Time":"3:11pm","Ask":"1.3620","Bid":"1.3610"},{"id":"USDBOB","Name":"USD\/BOB","Rate":"6.9000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"7.0500","Bid":"6.9000"},{"id":"USDBRL","Name":"USD\/BRL","Rate":"3.1513","Date":"8\/22\/2017","Time":"3:12pm","Ask":"3.1533","Bid":"3.1513"},{"id":"USDBSD","Name":"USD\/BSD","Rate":"1.0000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"1.0050","Bid":"1.0000"},{"id":"USDBTC","Name":"USD\/BTC","Rate":"0.0003","Date":"8\/22\/2017","Time":"3:11pm","Ask":"0.0004","Bid":"0.0003"},{"id":"USDBTN","Name":"USD\/BTN","Rate":"64.1000","Date":"8\/22\/2017","Time":"7:46am","Ask":"64.2000","Bid":"64.1000"},{"id":"USDBWP","Name":"USD\/BWP","Rate":"10.1783","Date":"8\/22\/2017","Time":"9:30am","Ask":"10.1883","Bid":"10.1783"},{"id":"USDBYR","Name":"USD\/BYR","Rate":"20020.0000","Date":"6\/30\/2016","Time":"2:27pm","Ask":"20045.0000","Bid":"20020.0000"},{"id":"USDBZD","Name":"USD\/BZD","Rate":"1.9977","Date":"8\/22\/2017","Time":"2:25pm","Ask":"2.0327","Bid":"1.9977"},{"id":"USDCAD","Name":"USD\/CAD","Rate":"1.2534","Date":"8\/22\/2017","Time":"3:12pm","Ask":"1.2535","Bid":"1.2534"},{"id":"USDCDF","Name":"USD\/CDF","Rate":"1540.6400","Date":"8\/22\/2017","Time":"2:25pm","Ask":"1550.6400","Bid":"1540.6400"},{"id":"USDCHF","Name":"USD\/CHF","Rate":"0.9679","Date":"8\/22\/2017","Time":"3:12pm","Ask":"0.9679","Bid":"0.9679"},{"id":"USDCLF","Name":"USD\/CLF","Rate":"0.0239","Date":"8\/22\/2017","Time":"2:55pm","Ask":"0.0244","Bid":"0.0239"},{"id":"USDCLP","Name":"USD\/CLP","Rate":"641.3000","Date":"8\/22\/2017","Time":"3:12pm","Ask":"641.7000","Bid":"641.3000"},{"id":"USDCNY","Name":"USD\/CNY","Rate":"6.6600","Date":"8\/22\/2017","Time":"3:01pm","Ask":"6.6648","Bid":"6.6600"},{"id":"USDCOP","Name":"USD\/COP","Rate":"2984.3000","Date":"8\/22\/2017","Time":"3:12pm","Ask":"2986.3000","Bid":"2984.3000"},{"id":"USDCRC","Name":"USD\/CRC","Rate":"570.4000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"580.4000","Bid":"570.4000"},{"id":"USDCUC","Name":"USD\/CUC","Rate":"0.9950","Date":"8\/22\/2017","Time":"3:00pm","Ask":"1.0050","Bid":"0.9950"},{"id":"USDCUP","Name":"USD\/CUP","Rate":"1.0000","Date":"8\/22\/2017","Time":"3:00pm","Ask":"N\/A","Bid":"1.0000"},{"id":"USDCVE","Name":"USD\/CVE","Rate":"93.8100","Date":"8\/22\/2017","Time":"3:12pm","Ask":"94.0600","Bid":"93.8100"},{"id":"USDCZK","Name":"USD\/CZK","Rate":"22.1898","Date":"8\/22\/2017","Time":"3:12pm","Ask":"22.1966","Bid":"22.1898"},{"id":"USDDJF","Name":"USD\/DJF","Rate":"178.0000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"179.0000","Bid":"178.0000"},{"id":"USDDKK","Name":"USD\/DKK","Rate":"6.3266","Date":"8\/22\/2017","Time":"3:12pm","Ask":"6.3275","Bid":"6.3266"},{"id":"USDDOP","Name":"USD\/DOP","Rate":"46.9700","Date":"8\/22\/2017","Time":"2:25pm","Ask":"47.2700","Bid":"46.9700"},{"id":"USDDZD","Name":"USD\/DZD","Rate":"109.8210","Date":"8\/22\/2017","Time":"3:12pm","Ask":"111.8210","Bid":"109.8210"},{"id":"USDEEK","Name":"N\/A","Rate":"N\/A","Date":"N\/A","Time":"N\/A","Ask":"N\/A","Bid":"N\/A"},{"id":"USDEGP","Name":"USD\/EGP","Rate":"17.7100","Date":"8\/20\/2017","Time":"7:46pm","Ask":"18.7100","Bid":"17.7100"},{"id":"USDERN","Name":"USD\/ERN","Rate":"15.2800","Date":"8\/22\/2017","Time":"2:25pm","Ask":"15.4800","Bid":"15.2800"},{"id":"USDETB","Name":"USD\/ETB","Rate":"23.2662","Date":"8\/22\/2017","Time":"1:00pm","Ask":"23.7315","Bid":"23.2662"},{"id":"USDEUR","Name":"USD\/EUR","Rate":"0.8505","Date":"8\/22\/2017","Time":"3:12pm","Ask":"0.8510","Bid":"0.8505"},{"id":"USDFJD","Name":"USD\/FJD","Rate":"2.0150","Date":"8\/8\/2017","Time":"6:41pm","Ask":"2.0300","Bid":"2.0150"},{"id":"USDFKP","Name":"USD\/FKP","Rate":"0.7790","Date":"8\/22\/2017","Time":"1:00pm","Ask":"0.7800","Bid":"0.7790"},{"id":"USDGBP","Name":"USD\/GBP","Rate":"0.7798","Date":"8\/22\/2017","Time":"3:12pm","Ask":"0.7798","Bid":"0.7798"},{"id":"USDGEL","Name":"USD\/GEL","Rate":"2.3810","Date":"8\/21\/2017","Time":"9:00pm","Ask":"2.4010","Bid":"2.3810"},{"id":"USDGGP","Name":"N\/A","Rate":"N\/A","Date":"N\/A","Time":"N\/A","Ask":"N\/A","Bid":"N\/A"},{"id":"USDGHS","Name":"USD\/GHS","Rate":"4.4335","Date":"8\/22\/2017","Time":"3:06pm","Ask":"4.4535","Bid":"4.4335"},{"id":"USDGIP","Name":"USD\/GIP","Rate":"0.7793","Date":"8\/22\/2017","Time":"1:00pm","Ask":"0.7798","Bid":"0.7793"},{"id":"USDGMD","Name":"USD\/GMD","Rate":"45.0000","Date":"8\/8\/2017","Time":"5:06pm","Ask":"47.2500","Bid":"45.0000"},{"id":"USDGNF","Name":"USD\/GNF","Rate":"8841.0000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"8941.0000","Bid":"8841.0000"},{"id":"USDGTQ","Name":"USD\/GTQ","Rate":"7.2720","Date":"8\/22\/2017","Time":"2:25pm","Ask":"7.2750","Bid":"7.2720"},{"id":"USDGYD","Name":"USD\/GYD","Rate":"204.0400","Date":"8\/22\/2017","Time":"2:25pm","Ask":"209.0400","Bid":"204.0400"},{"id":"USDHKD","Name":"USD\/HKD","Rate":"7.8261","Date":"8\/22\/2017","Time":"3:12pm","Ask":"7.8265","Bid":"7.8261"},{"id":"USDHNL","Name":"USD\/HNL","Rate":"23.3150","Date":"8\/22\/2017","Time":"2:25pm","Ask":"23.4150","Bid":"23.3150"},{"id":"USDHRK","Name":"USD\/HRK","Rate":"6.2644","Date":"8\/22\/2017","Time":"3:12pm","Ask":"6.3389","Bid":"6.2644"},{"id":"USDHTG","Name":"USD\/HTG","Rate":"61.8500","Date":"8\/22\/2017","Time":"2:25pm","Ask":"62.8500","Bid":"61.8500"},{"id":"USDHUF","Name":"USD\/HUF","Rate":"258.0600","Date":"8\/22\/2017","Time":"3:12pm","Ask":"258.3800","Bid":"258.0600"},{"id":"USDIDR","Name":"USD\/IDR","Rate":"13332.0000","Date":"8\/22\/2017","Time":"3:09pm","Ask":"13354.0000","Bid":"13332.0000"},{"id":"USDILS","Name":"USD\/ILS","Rate":"3.6147","Date":"8\/22\/2017","Time":"3:12pm","Ask":"3.6247","Bid":"3.6147"},{"id":"USDIMP","Name":"N\/A","Rate":"N\/A","Date":"N\/A","Time":"N\/A","Ask":"N\/A","Bid":"N\/A"},{"id":"USDINR","Name":"USD\/INR","Rate":"64.1300","Date":"8\/22\/2017","Time":"3:12pm","Ask":"64.1500","Bid":"64.1300"},{"id":"USDIQD","Name":"USD\/IQD","Rate":"1166.0000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"1168.0000","Bid":"1166.0000"},{"id":"USDIRR","Name":"USD\/IRR","Rate":"33003.0000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"33053.0000","Bid":"33003.0000"},{"id":"USDISK","Name":"USD\/ISK","Rate":"105.6800","Date":"8\/22\/2017","Time":"12:45pm","Ask":"106.1800","Bid":"105.6800"},{"id":"USDJEP","Name":"N\/A","Rate":"N\/A","Date":"N\/A","Time":"N\/A","Ask":"N\/A","Bid":"N\/A"},{"id":"USDJMD","Name":"USD\/JMD","Rate":"127.1800","Date":"8\/22\/2017","Time":"2:25pm","Ask":"127.6800","Bid":"127.1800"},{"id":"USDJOD","Name":"USD\/JOD","Rate":"0.7075","Date":"8\/22\/2017","Time":"2:25pm","Ask":"0.7090","Bid":"0.7075"},{"id":"USDJPY","Name":"USD\/JPY","Rate":"109.3490","Date":"8\/22\/2017","Time":"3:12pm","Ask":"109.3600","Bid":"109.3490"},{"id":"USDKES","Name":"USD\/KES","Rate":"102.9500","Date":"8\/22\/2017","Time":"2:25pm","Ask":"103.2500","Bid":"102.9500"},{"id":"USDKGS","Name":"USD\/KGS","Rate":"68.6360","Date":"8\/22\/2017","Time":"11:00am","Ask":"68.6860","Bid":"68.6360"},{"id":"USDKHR","Name":"USD\/KHR","Rate":"4110.0000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"4120.0000","Bid":"4110.0000"},{"id":"USDKMF","Name":"USD\/KMF","Rate":"417.9000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"418.8500","Bid":"417.9000"},{"id":"USDKPW","Name":"USD\/KPW","Rate":"900.0000","Date":"8\/22\/2017","Time":"3:00pm","Ask":"N\/A","Bid":"900.0000"},{"id":"USDKRW","Name":"USD\/KRW","Rate":"1132.2700","Date":"8\/22\/2017","Time":"3:12pm","Ask":"1133.2700","Bid":"1132.2700"},{"id":"USDKWD","Name":"USD\/KWD","Rate":"0.3017","Date":"8\/22\/2017","Time":"2:25pm","Ask":"0.3037","Bid":"0.3017"},{"id":"USDKYD","Name":"USD\/KYD","Rate":"0.8200","Date":"8\/22\/2017","Time":"3:00pm","Ask":"N\/A","Bid":"0.8200"},{"id":"USDKZT","Name":"USD\/KZT","Rate":"332.8100","Date":"8\/22\/2017","Time":"2:25pm","Ask":"332.8600","Bid":"332.8100"},{"id":"USDLAK","Name":"USD\/LAK","Rate":"8267.0000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"8302.0000","Bid":"8267.0000"},{"id":"USDLBP","Name":"USD\/LBP","Rate":"1505.5000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"1512.5000","Bid":"1505.5000"},{"id":"USDLKR","Name":"USD\/LKR","Rate":"152.9100","Date":"8\/22\/2017","Time":"12:33pm","Ask":"153.1000","Bid":"152.9100"},{"id":"USDLRD","Name":"USD\/LRD","Rate":"114.4000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"115.4000","Bid":"114.4000"},{"id":"USDLSL","Name":"USD\/LSL","Rate":"13.4100","Date":"8\/8\/2017","Time":"6:21pm","Ask":"13.4200","Bid":"13.4100"},{"id":"USDLTL","Name":"USD\/LTL","Rate":"3.0487","Date":"6\/22\/2015","Time":"9:39am","Ask":"3.0491","Bid":"3.0487"},{"id":"USDLVL","Name":"USD\/LVL","Rate":"0.6205","Date":"6\/22\/2015","Time":"9:37am","Ask":"0.6206","Bid":"0.6205"},{"id":"USDLYD","Name":"USD\/LYD","Rate":"1.3657","Date":"8\/22\/2017","Time":"2:25pm","Ask":"1.3727","Bid":"1.3657"},{"id":"USDMAD","Name":"USD\/MAD","Rate":"9.4689","Date":"8\/22\/2017","Time":"3:12pm","Ask":"9.4789","Bid":"9.4689"},{"id":"USDMDL","Name":"USD\/MDL","Rate":"17.8350","Date":"8\/22\/2017","Time":"2:25pm","Ask":"17.9350","Bid":"17.8350"},{"id":"USDMGA","Name":"USD\/MGA","Rate":"3185.0000","Date":"6\/12\/2017","Time":"5:52pm","Ask":"3220.0000","Bid":"3185.0000"},{"id":"USDMKD","Name":"USD\/MKD","Rate":"52.1000","Date":"8\/22\/2017","Time":"3:12pm","Ask":"52.4000","Bid":"52.1000"},{"id":"USDMMK","Name":"USD\/MMK","Rate":"1354.0000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"1358.0000","Bid":"1354.0000"},{"id":"USDMNT","Name":"USD\/MNT","Rate":"2437.0000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"2444.0000","Bid":"2437.0000"},{"id":"USDMOP","Name":"USD\/MOP","Rate":"8.0607","Date":"8\/22\/2017","Time":"3:10pm","Ask":"8.0617","Bid":"8.0607"},{"id":"USDMRO","Name":"USD\/MRO","Rate":"361.0000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"366.0000","Bid":"361.0000"},{"id":"USDMTL","Name":"N\/A","Rate":"N\/A","Date":"N\/A","Time":"N\/A","Ask":"N\/A","Bid":"N\/A"},{"id":"USDMUR","Name":"USD\/MUR","Rate":"33.1400","Date":"8\/22\/2017","Time":"2:25pm","Ask":"34.1400","Bid":"33.1400"},{"id":"USDMVR","Name":"USD\/MVR","Rate":"15.5400","Date":"8\/22\/2017","Time":"2:25pm","Ask":"15.7400","Bid":"15.5400"},{"id":"USDMWK","Name":"USD\/MWK","Rate":"715.9300","Date":"8\/22\/2017","Time":"2:25pm","Ask":"735.9300","Bid":"715.9300"},{"id":"USDMXN","Name":"USD\/MXN","Rate":"17.6548","Date":"8\/22\/2017","Time":"3:12pm","Ask":"17.6555","Bid":"17.6548"},{"id":"USDMYR","Name":"USD\/MYR","Rate":"4.2778","Date":"8\/22\/2017","Time":"2:58pm","Ask":"4.2828","Bid":"4.2778"},{"id":"USDMZN","Name":"USD\/MZN","Rate":"60.7000","Date":"8\/22\/2017","Time":"2:49pm","Ask":"61.7000","Bid":"60.7000"},{"id":"USDNAD","Name":"USD\/NAD","Rate":"13.2000","Date":"8\/22\/2017","Time":"3:12pm","Ask":"13.2030","Bid":"13.2000"},{"id":"USDNGN","Name":"USD\/NGN","Rate":"364.9000","Date":"8\/11\/2017","Time":"3:09am","Ask":"365.9000","Bid":"364.9000"},{"id":"USDNIO","Name":"USD\/NIO","Rate":"30.2559","Date":"8\/22\/2017","Time":"7:21am","Ask":"30.2569","Bid":"30.2559"},{"id":"USDNOK","Name":"USD\/NOK","Rate":"7.9109","Date":"8\/22\/2017","Time":"3:12pm","Ask":"7.9126","Bid":"7.9109"},{"id":"USDNPR","Name":"USD\/NPR","Rate":"102.2500","Date":"8\/22\/2017","Time":"12:29pm","Ask":"102.8500","Bid":"102.2500"},{"id":"USDNZD","Name":"USD\/NZD","Rate":"1.3704","Date":"8\/22\/2017","Time":"3:12pm","Ask":"1.3714","Bid":"1.3704"},{"id":"USDOMR","Name":"USD\/OMR","Rate":"0.3848","Date":"8\/22\/2017","Time":"2:25pm","Ask":"0.3850","Bid":"0.3848"},{"id":"USDPAB","Name":"USD\/PAB","Rate":"1.0000","Date":"8\/22\/2017","Time":"3:00pm","Ask":"N\/A","Bid":"1.0000"},{"id":"USDPEN","Name":"USD\/PEN","Rate":"3.2375","Date":"8\/22\/2017","Time":"3:02pm","Ask":"3.2425","Bid":"3.2375"},{"id":"USDPGK","Name":"USD\/PGK","Rate":"3.1696","Date":"8\/22\/2017","Time":"1:00pm","Ask":"3.1746","Bid":"3.1696"},{"id":"USDPHP","Name":"USD\/PHP","Rate":"51.2800","Date":"8\/22\/2017","Time":"3:12pm","Ask":"51.3300","Bid":"51.2800"},{"id":"USDPKR","Name":"USD\/PKR","Rate":"105.3000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"105.5000","Bid":"105.3000"},{"id":"USDPLN","Name":"USD\/PLN","Rate":"3.6372","Date":"8\/22\/2017","Time":"3:12pm","Ask":"3.6381","Bid":"3.6372"},{"id":"USDPYG","Name":"USD\/PYG","Rate":"5586.7998","Date":"8\/22\/2017","Time":"2:50pm","Ask":"5636.7998","Bid":"5586.7998"},{"id":"USDQAR","Name":"USD\/QAR","Rate":"3.6398","Date":"8\/22\/2017","Time":"2:25pm","Ask":"3.6408","Bid":"3.6398"},{"id":"USDRON","Name":"USD\/RON","Rate":"3.8979","Date":"8\/22\/2017","Time":"3:12pm","Ask":"3.9029","Bid":"3.8979"},{"id":"USDRSD","Name":"USD\/RSD","Rate":"100.7997","Date":"8\/22\/2017","Time":"9:30am","Ask":"101.4063","Bid":"100.7997"},{"id":"USDRUB","Name":"USD\/RUB","Rate":"58.9852","Date":"8\/22\/2017","Time":"3:12pm","Ask":"58.9950","Bid":"58.9852"},{"id":"USDRWF","Name":"USD\/RWF","Rate":"825.5600","Date":"8\/22\/2017","Time":"2:25pm","Ask":"840.5600","Bid":"825.5600"},{"id":"USDSAR","Name":"USD\/SAR","Rate":"3.7499","Date":"8\/22\/2017","Time":"2:55pm","Ask":"3.7504","Bid":"3.7499"},{"id":"USDSBD","Name":"USD\/SBD","Rate":"7.7494","Date":"8\/8\/2017","Time":"6:45pm","Ask":"7.7544","Bid":"7.7494"},{"id":"USDSCR","Name":"USD\/SCR","Rate":"13.5720","Date":"8\/22\/2017","Time":"2:25pm","Ask":"13.7720","Bid":"13.5720"},{"id":"USDSDG","Name":"USD\/SDG","Rate":"6.6598","Date":"8\/22\/2017","Time":"2:25pm","Ask":"6.6928","Bid":"6.6598"},{"id":"USDSEK","Name":"USD\/SEK","Rate":"8.1095","Date":"8\/22\/2017","Time":"3:12pm","Ask":"8.1110","Bid":"8.1095"},{"id":"USDSGD","Name":"USD\/SGD","Rate":"1.3616","Date":"8\/22\/2017","Time":"3:12pm","Ask":"1.3617","Bid":"1.3616"},{"id":"USDSHP","Name":"USD\/SHP","Rate":"0.7793","Date":"8\/22\/2017","Time":"1:00pm","Ask":"0.7798","Bid":"0.7793"},{"id":"USDSLL","Name":"USD\/SLL","Rate":"7500.0000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"7600.0000","Bid":"7500.0000"},{"id":"USDSOS","Name":"USD\/SOS","Rate":"559.0000","Date":"8\/8\/2017","Time":"6:25pm","Ask":"629.0000","Bid":"559.0000"},{"id":"USDSRD","Name":"USD\/SRD","Rate":"7.3800","Date":"8\/22\/2017","Time":"2:25pm","Ask":"7.4300","Bid":"7.3800"},{"id":"USDSTD","Name":"USD\/STD","Rate":"20844.0000","Date":"8\/22\/2017","Time":"3:12pm","Ask":"20894.0000","Bid":"20844.0000"},{"id":"USDSVC","Name":"USD\/SVC","Rate":"8.7500","Date":"8\/22\/2017","Time":"3:00pm","Ask":"N\/A","Bid":"8.7500"},{"id":"USDSYP","Name":"USD\/SYP","Rate":"514.9800","Date":"8\/22\/2017","Time":"2:25pm","Ask":"515.4800","Bid":"514.9800"},{"id":"USDSZL","Name":"USD\/SZL","Rate":"13.2000","Date":"8\/22\/2017","Time":"3:12pm","Ask":"13.2500","Bid":"13.2000"},{"id":"USDTHB","Name":"USD\/THB","Rate":"33.2300","Date":"8\/22\/2017","Time":"3:12pm","Ask":"33.2600","Bid":"33.2300"},{"id":"USDTJS","Name":"USD\/TJS","Rate":"8.8079","Date":"8\/22\/2017","Time":"3:00am","Ask":"8.8089","Bid":"8.8079"},{"id":"USDTMT","Name":"USD\/TMT","Rate":"3.4000","Date":"8\/8\/2017","Time":"6:14pm","Ask":"3.6000","Bid":"3.4000"},{"id":"USDTND","Name":"USD\/TND","Rate":"2.4501","Date":"8\/22\/2017","Time":"3:12pm","Ask":"2.4521","Bid":"2.4501"},{"id":"USDTOP","Name":"USD\/TOP","Rate":"2.2084","Date":"8\/22\/2017","Time":"2:55pm","Ask":"2.2134","Bid":"2.2084"},{"id":"USDTRY","Name":"USD\/TRY","Rate":"3.4978","Date":"8\/22\/2017","Time":"3:12pm","Ask":"3.4980","Bid":"3.4978"},{"id":"USDTTD","Name":"USD\/TTD","Rate":"6.7395","Date":"8\/22\/2017","Time":"2:25pm","Ask":"6.7895","Bid":"6.7395"},{"id":"USDTWD","Name":"USD\/TWD","Rate":"30.2730","Date":"8\/22\/2017","Time":"3:12pm","Ask":"30.3030","Bid":"30.2730"},{"id":"USDTZS","Name":"USD\/TZS","Rate":"2232.0000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"2239.0000","Bid":"2232.0000"},{"id":"USDUAH","Name":"USD\/UAH","Rate":"25.4500","Date":"8\/22\/2017","Time":"2:25pm","Ask":"25.7000","Bid":"25.4500"},{"id":"USDUGX","Name":"USD\/UGX","Rate":"3589.0000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"3599.0000","Bid":"3589.0000"},{"id":"USDUSD","Name":"USD\/USD","Rate":"1.0000","Date":"N\/A","Time":"N\/A","Ask":"1.0000","Bid":"1.0000"},{"id":"USDUYU","Name":"USD\/UYU","Rate":"28.7600","Date":"8\/22\/2017","Time":"2:25pm","Ask":"28.8600","Bid":"28.7600"},{"id":"USDUZS","Name":"USD\/UZS","Rate":"4120.0000","Date":"8\/8\/2017","Time":"6:35pm","Ask":"4130.0000","Bid":"4120.0000"},{"id":"USDVEF","Name":"USD\/VEF","Rate":"9.9750","Date":"8\/22\/2017","Time":"2:25pm","Ask":"9.9850","Bid":"9.9750"},{"id":"USDVND","Name":"USD\/VND","Rate":"22727.0000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"22737.0000","Bid":"22727.0000"},{"id":"USDVUV","Name":"USD\/VUV","Rate":"103.3300","Date":"8\/22\/2017","Time":"2:25pm","Ask":"105.3300","Bid":"103.3300"},{"id":"USDWST","Name":"USD\/WST","Rate":"2.5094","Date":"8\/22\/2017","Time":"2:55pm","Ask":"2.5144","Bid":"2.5094"},{"id":"USDXAF","Name":"USD\/XAF","Rate":"557.6100","Date":"8\/22\/2017","Time":"3:10pm","Ask":"558.6100","Bid":"557.6100"},{"id":"USDXAG","Name":"USD\/XAG","Rate":"0.0591","Date":"8\/22\/2017","Time":"3:11pm","Ask":"N\/A","Bid":"0.0591"},{"id":"USDXAU","Name":"USD\/XAU","Rate":"0.0008","Date":"8\/22\/2017","Time":"3:11pm","Ask":"N\/A","Bid":"0.0008"},{"id":"USDXCD","Name":"USD\/XCD","Rate":"2.7000","Date":"8\/22\/2017","Time":"3:00pm","Ask":"N\/A","Bid":"2.7000"},{"id":"USDXDR","Name":"USD\/XDR","Rate":"0.7099","Date":"8\/22\/2017","Time":"2:10pm","Ask":"N\/A","Bid":"0.7099"},{"id":"USDXOF","Name":"USD\/XOF","Rate":"557.9800","Date":"8\/22\/2017","Time":"3:12pm","Ask":"559.9800","Bid":"557.9800"},{"id":"USDXPF","Name":"USD\/XPF","Rate":"100.9600","Date":"8\/22\/2017","Time":"3:10pm","Ask":"101.9600","Bid":"100.9600"},{"id":"USDYER","Name":"USD\/YER","Rate":"249.9000","Date":"8\/22\/2017","Time":"2:25pm","Ask":"250.0000","Bid":"249.9000"},{"id":"USDZAR","Name":"USD\/ZAR","Rate":"13.2036","Date":"8\/22\/2017","Time":"3:12pm","Ask":"13.2073","Bid":"13.2036"},{"id":"USDZMK","Name":"N\/A","Rate":"N\/A","Date":"N\/A","Time":"N\/A","Ask":"N\/A","Bid":"N\/A"},{"id":"USDZMW","Name":"USD\/ZMW","Rate":"8.9900","Date":"8\/22\/2017","Time":"2:52pm","Ask":"9.1900","Bid":"8.9900"},{"id":"USDZWL","Name":"USD\/ZWL","Rate":"322.3550","Date":"7\/1\/2016","Time":"0:13am","Ask":"325.5800","Bid":"322.3550"},{"id":"=X","Name":"N\/A","Rate":"N\/A","Date":"N\/A","Time":"N\/A","Ask":"N\/A","Bid":"N\/A"}]}}} --------------------------------------------------------------------------------