oanda_exchange 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
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,9 @@
1
+ require "money"
2
+
3
+ class OandaBank < Money::Bank::Base
4
+
5
+ def exchange_with(from, to_currency)
6
+ Money.new(Oanda.exchange(from.currency.to_s, :to => to_currency.to_s, :amount => from) * 100, to_currency.to_s)
7
+ end
8
+
9
+ 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
@@ -0,0 +1,3 @@
1
+ module OandaExchange
2
+ VERSION = "0.7.2"
3
+ end
@@ -0,0 +1,4 @@
1
+ require "oanda_exchange/config"
2
+ require "oanda_exchange/oanda"
3
+ require "oanda_exchange/oanda_bank"
4
+ require "oanda_exchange/stubs"
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: []