oanda_exchange 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/oanda_exchange/config.rb +47 -0
- data/lib/oanda_exchange/oanda.rb +115 -0
- data/lib/oanda_exchange/oanda_bank.rb +9 -0
- data/lib/oanda_exchange/stubs.rb +15 -0
- data/lib/oanda_exchange/version.rb +3 -0
- data/lib/oanda_exchange.rb +4 -0
- metadata +105 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2b1d160d29dac99403a86bc2394f350213463605
|
4
|
+
data.tar.gz: 19361f24d1c532b5e7ad41423da6e21e7d2cd342
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6f2818ace9293814792533b89598f1b1f2cb021cf707ad406e1f23290757b727132f456bbdf6ad3e43f30564083c21330c56f391162e6388c98973330ccaf39b
|
7
|
+
data.tar.gz: 994f549e9dcc730a400d72799ef50a44ed0aa82283f3f6d59aa737bfe84680cfde3c7c47d958305796003c2bd811461d8aa71d6a7691d1f09b1951d14827675a
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "logger"
|
2
|
+
require "active_support/core_ext/hash"
|
3
|
+
|
4
|
+
module OandaExchange
|
5
|
+
class Config
|
6
|
+
|
7
|
+
def self.get
|
8
|
+
@@config ||= YAML::load_file(File.join(root, "config", "oanda_api.yml")).symbolize_keys or raise Exception.new("Error on loading configuration file for OANDA API")
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.root
|
12
|
+
rails_root || "."
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.logger
|
16
|
+
@@logger ||= rails_logger || Logger.new(STDOUT)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.env
|
20
|
+
rails_env || ENV["ENV"] || "development"
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.rails_env
|
24
|
+
if defined?(Rails)
|
25
|
+
Rails.env
|
26
|
+
elsif defined?(RAILS_ENV)
|
27
|
+
RAILS_ENV
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.rails_root
|
32
|
+
if defined?(Rails)
|
33
|
+
Rails.root
|
34
|
+
elsif defined?(RAILS_ENV)
|
35
|
+
RAILS_ROOT
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.rails_logger
|
40
|
+
if defined?(Rails)
|
41
|
+
Rails.logger
|
42
|
+
elsif defined?(RAILS_DEFAULT_LOGGER)
|
43
|
+
RAILS_DEFAULT_LOGGER
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require "rest-client"
|
2
|
+
require "active_support/core_ext/object/blank"
|
3
|
+
require "active_support/core_ext/enumerable"
|
4
|
+
require "active_support/core_ext/big_decimal"
|
5
|
+
require "active_support/core_ext/hash/conversions"
|
6
|
+
|
7
|
+
class Oanda
|
8
|
+
|
9
|
+
attr_accessor :base_currency, :quote_currency, :date, :days, :amount, :response, :resp_hash, :interbank, :price
|
10
|
+
|
11
|
+
PRECISION = 8
|
12
|
+
|
13
|
+
def self.exchange(base_currency, options = {})
|
14
|
+
new.exchange(base_currency, options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.currencies
|
18
|
+
new.currencies
|
19
|
+
end
|
20
|
+
|
21
|
+
def exchange(base_currency, options = {})
|
22
|
+
raise Exception.new("no base currency specified") if base_currency.blank?
|
23
|
+
raise Exception.new("no quote currency specified") if options[:to].blank?
|
24
|
+
self.price = options[:price] == :midpoint ? [:ask, :bid] : [options[:price] || :bid]
|
25
|
+
self.base_currency = base_currency.to_s.upcase
|
26
|
+
self.quote_currency = options[:to].to_s.upcase
|
27
|
+
self.date = options[:date] || Date.today
|
28
|
+
self.days = options[:days] || 1
|
29
|
+
self.amount = options[:amount] || 1
|
30
|
+
self.interbank = options[:interbank] || 0
|
31
|
+
self.response = exchange_request(build_request)
|
32
|
+
self.resp_hash = Hash.from_xml(response)["RESPONSE"]
|
33
|
+
average_rate = calculate_average_rate
|
34
|
+
self.interbank = average_rate * interbank.to_f / 100
|
35
|
+
base_currency == quote_currency ? average_rate : average_rate - interbank
|
36
|
+
end
|
37
|
+
|
38
|
+
def currencies
|
39
|
+
self.response = currencies_request
|
40
|
+
self.resp_hash = Hash.from_xml response
|
41
|
+
extract_currencies
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def api_request(request_string, &block)
|
46
|
+
OandaExchange::Config.logger.debug "OANDA API: request body\n#{request_string}"
|
47
|
+
resp = yield request_string
|
48
|
+
OandaExchange::Config.logger.debug "OANDA API: response #{resp.code}\n#{resp.body}"
|
49
|
+
raise Exception.new("Unexpected response code from OANDA API. See log entries with debug level to get more information.") unless resp.code == 200
|
50
|
+
resp.body
|
51
|
+
end
|
52
|
+
|
53
|
+
def exchange_request(request_string)
|
54
|
+
api_request request_string do
|
55
|
+
OandaExchange::Config.logger.debug "OANDA API: request \n#{config[:exchange_service_url]}"
|
56
|
+
OandaExchange::Config.logger.info "OANDA API: requesting #{base_currency} conversion into #{quote_currency}"
|
57
|
+
RestClient.get "#{config[:exchange_service_url]}", :params => {:fxmlrequest => request_string}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def currencies_request
|
62
|
+
api_request "" do
|
63
|
+
OandaExchange::Config.logger.debug "OANDA API: request \n#{config[:currencies_url]}"
|
64
|
+
RestClient.get "#{config[:currencies_url]}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
protected
|
70
|
+
|
71
|
+
def extract_currencies
|
72
|
+
resp_hash['CURRENCYCODES']['CURRENCY'].inject({}) do |hash, node|
|
73
|
+
hash.merge node['CODE'] => node['COUNTRY']
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def calculate_average_rate
|
78
|
+
average extract_exchange_rates
|
79
|
+
end
|
80
|
+
|
81
|
+
def extract_exchange_rates
|
82
|
+
extract_rates.reject{|values| values.include?("na")}.map do |values|
|
83
|
+
average values.map{|v| BigDecimal.new(v, PRECISION)}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def average(values)
|
88
|
+
(values.sum / values.size).round(PRECISION) rescue BigDecimal.new('0', PRECISION)
|
89
|
+
end
|
90
|
+
|
91
|
+
def extract_rates
|
92
|
+
rates = resp_hash["CONVERSION"].is_a?(Array) ? resp_hash["CONVERSION"] : [resp_hash["CONVERSION"]]
|
93
|
+
rates.map{|hash| price_value(hash)}
|
94
|
+
end
|
95
|
+
|
96
|
+
def price_value(hash)
|
97
|
+
price.map{|p| hash[p.to_s.upcase]}
|
98
|
+
end
|
99
|
+
|
100
|
+
def build_request
|
101
|
+
{
|
102
|
+
:date => date.strftime('%m/%d/%Y'),
|
103
|
+
:client_id => config[:client_id],
|
104
|
+
:exch => base_currency,
|
105
|
+
:expr => quote_currency,
|
106
|
+
:nprices => days,
|
107
|
+
:amount => amount
|
108
|
+
}.to_xml(:dasherize => false, :skip_types => true, :root => :convert)
|
109
|
+
end
|
110
|
+
|
111
|
+
def config
|
112
|
+
OandaExchange::Config.get
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module OandaExchange::Stubs
|
2
|
+
require 'rspec/mocks/standalone' if defined? RSpec
|
3
|
+
|
4
|
+
DEFAULT_CURRENCIES = {"USD" => "US Dollar", "EUR" => "Euro"}
|
5
|
+
DEFAULT_RATES = {"USD" => 1, "other" => 1.5}
|
6
|
+
|
7
|
+
def self.stub!(options = {})
|
8
|
+
raise "RSpec stub library required" unless Object.respond_to? :stub!
|
9
|
+
rates = options[:rates] || DEFAULT_RATES
|
10
|
+
Oanda.stub!(:exchange) do |cur, opts|
|
11
|
+
BigDecimal.new((opts[:amount] || 0).to_s, 5) * (rates[cur] || rates["other"] || 1)
|
12
|
+
end
|
13
|
+
Oanda.stub!(:currencies).and_return(options[:currencies] || DEFAULT_CURRENCIES)
|
14
|
+
end
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: oanda_exchange
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.7.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dieter Pisarewski
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: builder
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: money
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rest-client
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.6'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.6'
|
69
|
+
description: OANDA Exchange API
|
70
|
+
email:
|
71
|
+
- dieter.pisarewski@arvatosystems.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- lib/oanda_exchange/config.rb
|
77
|
+
- lib/oanda_exchange/oanda.rb
|
78
|
+
- lib/oanda_exchange/oanda_bank.rb
|
79
|
+
- lib/oanda_exchange/stubs.rb
|
80
|
+
- lib/oanda_exchange/version.rb
|
81
|
+
- lib/oanda_exchange.rb
|
82
|
+
homepage: http://www.arvatosystems-us.com/
|
83
|
+
licenses: []
|
84
|
+
metadata: {}
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
requirements: []
|
100
|
+
rubyforge_project:
|
101
|
+
rubygems_version: 2.0.14
|
102
|
+
signing_key:
|
103
|
+
specification_version: 4
|
104
|
+
summary: API for OANDA Exchange Services
|
105
|
+
test_files: []
|