├── .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 | [](https://github.com/danielme85/laravel-cconverter)
4 | [](https://packagist.org/packages/danielme85/laravel-cconverter)
5 | [](https://packagist.org/packages/danielme85/laravel-cconverter)
6 | [](https://github.com/danielme85/laravel-cconverter)
7 | [](https://travis-ci.org/danielme85/laravel-cconverter)
8 | [](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"}]}}}
--------------------------------------------------------------------------------