em-betfair 0.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.
Files changed (32) hide show
  1. data/.gitignore +3 -0
  2. data/Gemfile +8 -0
  3. data/README.md +47 -0
  4. data/Rakefile +1 -0
  5. data/em-betfair.gemspec +25 -0
  6. data/examples/scrape_betfair.rb +88 -0
  7. data/lib/em-betfair/betfair_client.rb +126 -0
  8. data/lib/em-betfair/response.rb +41 -0
  9. data/lib/em-betfair/response_parser.rb +135 -0
  10. data/lib/em-betfair/soap_renderer.rb +29 -0
  11. data/lib/em-betfair/views/exchange/get_all_markets.haml +23 -0
  12. data/lib/em-betfair/views/exchange/get_market.haml +12 -0
  13. data/lib/em-betfair/views/exchange/get_market_prices_compressed.haml +12 -0
  14. data/lib/em-betfair/views/exchange/get_market_traded_volume_compressed.haml +12 -0
  15. data/lib/em-betfair/views/global/get_all_event_types.haml +12 -0
  16. data/lib/em-betfair/views/global/login.haml +11 -0
  17. data/lib/em-betfair/views/global/retrieve_limb_message.haml +9 -0
  18. data/lib/em-betfair/views/global/submit_limb_message.haml +14 -0
  19. data/lib/em-betfair.rb +4 -0
  20. data/spec/functional/betfair_client_spec.rb +149 -0
  21. data/spec/remote/betfair_client_spec.rb +69 -0
  22. data/spec/spec_helper.rb +17 -0
  23. data/spec/support/canned_responses/get_all_markets.xml +18 -0
  24. data/spec/support/canned_responses/get_all_markets_no_session.xml +18 -0
  25. data/spec/support/canned_responses/get_market.xml +3 -0
  26. data/spec/support/canned_responses/get_market_prices_compressed.xml +18 -0
  27. data/spec/support/canned_responses/get_market_traded_volume_compressed.xml +20 -0
  28. data/spec/support/canned_responses/login_failed.xml +19 -0
  29. data/spec/support/canned_responses/login_ok.xml +19 -0
  30. data/spec/support/canned_responses/soap_fault.xml +9 -0
  31. data/spec/unit/response_parser_spec.rb +45 -0
  32. metadata +143 -0
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .DS_Store
2
+ Gemfile.lock
3
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # A sample Gemfile
2
+ source "http://rubygems.org"
3
+
4
+ gem "eventmachine"
5
+ gem "em-http-request"
6
+ gem "rspec"
7
+ gem "haml"
8
+ gem "nokogiri"
data/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # Betfair API client using Eventmachine and EM-Http
2
+
3
+ em-betfair is a work in progress evented client for the Betfair API. The following API calls have been implemented :
4
+
5
+ - login
6
+ - getMarket
7
+ - getAllMarkets
8
+ - getMarketPricesCompressed
9
+ - getMarketTradedVolumeCompressed
10
+
11
+ # Usage
12
+
13
+ gem install em-betfair
14
+
15
+ gem "em-betfair", "~> 0.1"
16
+
17
+ Create an instance of the client
18
+
19
+ config = {
20
+ "username" => "<YOUR BETFAIR USERNAME>",
21
+ "password" => "<YOUR BETFAIR PASSWORD>",
22
+ "product_id" => "<YOUR BETFAIR PRODUCTID>",
23
+ "exchange_endpoint" => "https://api.betfair.com/exchange/v5/BFExchangeService",
24
+ "global_endpoint" => "https://api.betfair.com/global/v3/BFGlobalService"
25
+ }
26
+ bf_client = Betfair::Client.new(config)
27
+
28
+ Making a call to the API:
29
+
30
+ EM::run {
31
+ bf_client.get_all_markets do |rsp|
32
+
33
+ rsp.raw_response # access the raw response body
34
+ rsp.parsed_response # access the Nokogiri XML object of the raw response
35
+ rsp.hash_response # access a hash of the response data
36
+
37
+ rsp.successfull # boolean for success
38
+ rsp.error # API error messge if not successfull
39
+
40
+ end
41
+ }
42
+
43
+ Note, logging in to the API is handled internally by the client.
44
+
45
+ # Ruby versions
46
+
47
+ Tested on 1.9.2 but should work on 1.8.7 too.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "em-betfair"
5
+ s.version = "0.2"
6
+ s.authors = ["George Sheppard"]
7
+ s.email = ["george@fuzzmonkey.co.uk"]
8
+ s.homepage = "https://github.com/fuzzmonkey/em-betfair"
9
+ s.summary = %q{Betfair API client using Eventmachine and EM-Http}
10
+ s.description = %q{em-betfair is a work in progress evented client for the Betfair API}
11
+
12
+ s.rubyforge_project = "em-betfair"
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_development_dependency "rspec"
20
+ s.add_runtime_dependency "eventmachine"
21
+ s.add_runtime_dependency "em-http-request"
22
+ s.add_runtime_dependency "haml"
23
+ s.add_runtime_dependency "nokogiri"
24
+
25
+ end
@@ -0,0 +1,88 @@
1
+ # Example script to scrape the Betfair API for prices and store them in redis as json strings.
2
+
3
+ # WARNING - Beware of the Betfair data usage limits!!!
4
+
5
+ require 'eventmachine'
6
+ require 'em-betfair'
7
+ require 'date'
8
+ require 'time'
9
+ require 'redis'
10
+ require 'json'
11
+
12
+ # Not requiring activesupport just to get ordanalize
13
+ class Fixnum
14
+ def ordinalize
15
+ if (11..13).include?(self % 100)
16
+ "#{self}th"
17
+ else
18
+ case self % 10
19
+ when 1; "#{self}st"
20
+ when 2; "#{self}nd"
21
+ when 3; "#{self}rd"
22
+ else "#{self}th"
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ EM::run {
29
+
30
+ config = {
31
+ "username" => "<YOUR BETFAIR USERNAME>",
32
+ "password" => "<YOUR BETFAIR PASSWORD>",
33
+ "product_id" => "<YOUR BETFAIR PRODUCTID>",
34
+ "exchange_endpoint" => "https://api.betfair.com/exchange/v5/BFExchangeService",
35
+ "global_endpoint" => "https://api.betfair.com/global/v3/BFGlobalService"
36
+ }
37
+
38
+ bf_client = Betfair::Client.new(config)
39
+ redis_client = Redis.new
40
+ timers = {}
41
+ num_timers = 0
42
+
43
+ # Fetch all the horse racing markets in the UK for today
44
+ bf_client.get_all_markets ["GBR"], [7], "#{Date.today} 00:00:00", "#{Date.today} 23:59:00" do |response|
45
+
46
+ response.hash_response["market_data"].each do |market_id,market_hash|
47
+
48
+ menu_path = market_hash["menu_path"]
49
+ track_name = menu_path.match(/\\.+\\.+\\(\w+\s{0,1}\w*)/)[1]
50
+
51
+ # Lets just fetch the 'real' markets rather than AvB, Antepost, Place etc
52
+ next unless track_name && !market_hash["name"].match(/To Be Placed/) && !menu_path.match(/ANTEPOST/) && !menu_path.match(/Forecast/) && track_name.match(/#{Date.today.day.ordinalize}/)
53
+
54
+ # Fetch the runners
55
+ bf_client.get_market market_id do |market_response|
56
+ market_details = market_response.hash_response
57
+ puts "Got market #{market_id} #{track_name} #{market_hash["name"]} #{Time.parse(market_details["market_time"])}"
58
+ runners = market_details["runners"]
59
+
60
+ # If the market is active, setup some periodical timers
61
+ next unless market_details["status"] == "ACTIVE"
62
+
63
+ # would be nice to get the data from getSilks here
64
+ redis_client.hset track_name, market_hash["name"], {"market_details" => market_details, "prices" => nil}.to_json
65
+
66
+ next if num_timers > 59 # free API restriction
67
+
68
+ # Update the odds every 60 seconds
69
+ timers[market_id] = EventMachine::PeriodicTimer.new(60) do
70
+ num_timers += 1
71
+ bf_client.get_market_prices_compressed market_id do |prices_response|
72
+ puts "Fetching prices for #{market_id}"
73
+ price_data = prices_response.hash_response
74
+ timers[market_id].cancel if timers[market_id] && price_data["status"] != "ACTIVE"
75
+ race = redis_client.hget track_name, market_hash["name"]
76
+ race_hash = JSON.parse(race)
77
+ race_hash["prices"] = price_data
78
+ redis_client.hset track_name, market_hash["name"], race_hash.to_json
79
+ end
80
+ end
81
+
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+
88
+ }
@@ -0,0 +1,126 @@
1
+ require 'uri'
2
+ require 'em-http'
3
+ require 'nokogiri'
4
+ #require 'tzinfo'
5
+
6
+ module Betfair
7
+
8
+ BETFAIR_TIME_ZONES = {"RSA"=>"Africa/Johannesburg", "AST"=>"US/Arizona", "MST"=>"US/Mountain", "JPT"=>"Japan", "HK"=>"Hongkong", "GMT"=>"GMT", "PKT"=>"Etc/GMT-5", "UAE"=>"Asia/Dubai", "CST"=>"US/Central", "AKST"=>"US/Alaska", "BRT"=>"Brazil/East", "INT"=>"Asia/Calcutta", "SMT"=>"America/Santiago", "MSK"=>"Europe/Moscow", "AWST"=>"Australia/Perth", "PST"=>"US/Pacific", "EST"=>"US/Eastern", "KMT"=>"Jamaica", "CET"=>"CET", "ANST"=>"Australia/Darwin", "ACST"=>"Australia/Adelaide", "NZT"=>"NZ", "UKT"=>"Europe/London", "AMT"=>"Brazil/West", "THAI"=>"Asia/Bangkok", "SJMT"=>"America/Costa_Rica", "HST"=>"US/Hawaii", "EET"=>"EET", "AEST"=>"Australia/Sydney", "IEST"=>"America/Indiana/Indianapolis", "AQST"=>"Australia/Queensland"}
9
+
10
+ class Client
11
+
12
+ attr_accessor :session_token
13
+
14
+ # config - hash of betfair credentials & API endpoints
15
+ # { "username" => "<YOUR BETFAIR USERNAME>", "password" => "<YOUR BETFAIR PASSWORD>", "product_id" => "<YOUR BETFAIR PRODUCTID>", "exchange_endpoint" => "https://api.betfair.com/exchange/v5/BFExchangeService", "global_endpoint" => "https://api.betfair.com/global/v3/BFGlobalService" }
16
+ def initialize config
17
+ @config = config
18
+ @session_token = nil
19
+ end
20
+
21
+ # Creates a session on the Betfair API, used by Betfair::Client internally to maintain session.
22
+ def login &block
23
+ build_request "global", "login", {"username" => @config["username"], "password" => @config["password"], "product_id" => @config["product_id"]}, block
24
+ end
25
+
26
+ # Returns all the available markets on Betfair.
27
+ #
28
+ # countries - array of ISO 3166-1 country codes
29
+ # event_type_ids - array of Betfair event ids
30
+ # to_date - DateTime
31
+ # from_date - DateTime
32
+ def get_all_markets countries=nil, event_type_ids=nil, to_date=nil, from_date=nil, &block
33
+ with_session do
34
+ build_request "exchange", "get_all_markets", {"countries" => countries, "event_type_ids" => event_type_ids, "to_date" => to_date, "from_date" => from_date}, block
35
+ end
36
+ end
37
+
38
+ # Returns the details of a specifc market
39
+ #
40
+ # market_id - Betfair market ID
41
+ def get_market market_id, &block
42
+ with_session do
43
+ build_request "exchange", "get_market", {"market_id" => market_id }, block
44
+ end
45
+ end
46
+
47
+ # Returns the compressed market prices
48
+ #
49
+ # market_id - Betfair market ID
50
+ # currency_code - three letter ISO 4217 country code
51
+ def get_market_prices_compressed market_id, currency_code=nil, &block
52
+ with_session do
53
+ build_request "exchange", "get_market_prices_compressed", {"market_id" => market_id, "currency_code" => currency_code}, block
54
+ end
55
+ end
56
+
57
+ # Returns the compressed traded volumes
58
+ #
59
+ # market_id - Betfair market ID
60
+ # currency_code - three letter ISO 4217 country code
61
+ def get_market_traded_volume_compressed market_id, currency_code=nil, &block
62
+ with_session do
63
+ build_request "exchange", "get_market_traded_volume_compressed", {"market_id" => market_id, "currency_code" => currency_code}, block
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ # Builds the EM::Http request object
70
+ #
71
+ # service_name - the endpoint to use (exchange or global)
72
+ # action - the API method to call on the API
73
+ # data - hash of parameters to populate the SOAP request
74
+ # block - the ballback for this request
75
+ def build_request service_name, action, data={}, block
76
+ request_data = { :data => data.merge!({"session_token" => @session_token}) }
77
+ soap_req = Betfair::SOAPRenderer.new( service_name, action ).render( request_data )
78
+ url = get_endpoint service_name
79
+ headers = { 'SOAPAction' => action, 'Accept-Encoding' => 'gzip,deflate', 'Content-type' => 'text/xml;charset=UTF-8' }
80
+ req = EventMachine::HttpRequest.new(url).post :body => soap_req, :head => headers
81
+ req.errback { block.call(Response.new(nil,nil,false,"Error connecting to the API")) }
82
+ req.callback { parse_response(req.response,block) }
83
+ end
84
+
85
+ # Parses the API response, building a response object
86
+ #
87
+ # raw_rsp - response body from EM:Http request
88
+ # block - callback for this request
89
+ def parse_response raw_rsp, block
90
+ parsed_response = Nokogiri::XML raw_rsp
91
+
92
+ soap_fault = parsed_response.xpath("//faultstring").first
93
+ if soap_fault
94
+ block.call(Response.new(raw_rsp,parsed_response,false,soap_fault.text))
95
+ return
96
+ end
97
+
98
+ api_error = parsed_response.xpath("//header/errorCode").text
99
+ method_error = parsed_response.xpath("//errorCode").last.text
100
+
101
+ error_rsp = api_error == "OK" ? method_error : api_error
102
+ unless api_error == "OK" && method_error == "OK"
103
+ @session_token = nil if [api_error,method_error].include?("NO_SESSION") # so we try and login on the next request
104
+ block.call(Response.new(raw_rsp,parsed_response,false,error_rsp))
105
+ return
106
+ end
107
+
108
+ @session_token = parsed_response.xpath("//sessionToken").text
109
+
110
+ block.call Response.new(raw_rsp,parsed_response,true)
111
+ end
112
+
113
+ def with_session
114
+ yield unless @session_token.nil?
115
+ login do |response|
116
+ yield
117
+ end
118
+ end
119
+
120
+ def get_endpoint service_name
121
+ return @config["#{service_name}_endpoint"]
122
+ end
123
+
124
+ end
125
+
126
+ end
@@ -0,0 +1,41 @@
1
+ # Stolen from Rails 3
2
+ def underscore(camel_cased_word)
3
+ camel_cased_word.to_s.gsub(/::/, '/').
4
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
5
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
6
+ tr("-", "_").
7
+ downcase
8
+ end
9
+
10
+ module Betfair
11
+
12
+ class Response
13
+ include ResponseParser
14
+
15
+ attr_accessor :raw_response # response string
16
+ attr_accessor :parsed_response # response xml
17
+ attr_accessor :successfull
18
+ attr_accessor :error
19
+
20
+ def initialize raw, parsed, successfull, error=""
21
+ @raw_response = raw
22
+ @parsed_response = parsed
23
+ @successfull = successfull
24
+ @error = error
25
+ end
26
+
27
+ # lazy loaded
28
+ def hash_response
29
+ method = get_response_type
30
+ self.send method.to_sym, self.parsed_response if method && self.respond_to?(method)
31
+ end
32
+
33
+ def get_response_type
34
+ return nil unless self.parsed_response.respond_to?(:xpath)
35
+ response_type = self.parsed_response.xpath("//ns:Envelope/ns:Body", "ns" => "http://schemas.xmlsoap.org/soap/envelope/").first.elements.first.name
36
+ underscore(response_type.gsub("Response",""))
37
+ end
38
+
39
+ end
40
+
41
+ end
@@ -0,0 +1,135 @@
1
+ module Betfair
2
+
3
+ # TODO - version this to handle changes in the API
4
+ # TODO - this might be nicer as a structs style setup. e.g
5
+ # markets_rsp = GetAllMarkets.new(parsed_response)
6
+ module ResponseParser
7
+
8
+ # TODO - handle timezones, return local & utc time
9
+ # tz = TZInfo::Timezone.get(new_time_zone)
10
+ # race_time = tz.utc_to_local(race_time)
11
+
12
+ # TODO - return values as proper types rather than strings
13
+
14
+ def login xml
15
+ {"currency" => xml.xpath("//currency").text}
16
+ end
17
+
18
+ def get_all_markets xml
19
+ market_data = xml.xpath("//marketData").text
20
+ all_markets_hash = {"market_data" => {}}
21
+ market_data.split(":").each do |market|
22
+ market_fields = market.split("~")
23
+ next unless market_fields.size >= 16 #incase they append more fields
24
+ market_hash = {}
25
+ market_hash["id"] = market_fields[0]
26
+ market_hash["name"] = market_fields[1]
27
+ market_hash["type"] = market_fields[2]
28
+ market_hash["status"] = market_fields[3]
29
+ market_hash["date"] = Time.at(market_fields[4].to_i/1000).utc #Epoc time
30
+ market_hash["menu_path"] = market_fields[5]
31
+ market_hash["event_hierarchy"] = market_fields[6]
32
+ market_hash["bet_delay"] = market_fields[7]
33
+ market_hash["exchange_id"] = market_fields[8]
34
+ market_hash["country_code"] = market_fields[9]
35
+ market_hash["last_refresh"] = Time.at(market_fields[10].to_i/1000).utc #Epoc time
36
+ market_hash["num_runners"] = market_fields[11]
37
+ market_hash["num_winners"] = market_fields[12]
38
+ market_hash["total_amount_matched"] = market_fields[13]
39
+ market_hash["bsp_market"] = market_fields[14] == "Y"
40
+ market_hash["turning_in_play"] = market_fields[15] == "Y"
41
+
42
+ all_markets_hash["market_data"][market_fields[0]] = market_hash
43
+ end
44
+ all_markets_hash
45
+ end
46
+
47
+ def get_market xml
48
+ market_hash = {}
49
+ market_hash["id"] = xml.xpath("//market/marketId").text
50
+ market_hash["status"] = xml.xpath("//market/marketStatus").text
51
+ market_hash["parent_id"] = xml.xpath("//market/parentEventId").text
52
+ market_hash["country_code"] = xml.xpath("//market/countryISO3").text
53
+ market_hash["event_type"] = xml.xpath("//market/eventTypeId").text
54
+ market_hash["base_rate"] = xml.xpath("//market/marketBaseRate").text
55
+ market_hash["market_name"] = xml.xpath("//market/name").text
56
+ market_hash["num_winners"] = xml.xpath("//market/numberOfWinners").text
57
+ market_hash["market_time"] = xml.xpath("//market/marketTime").text
58
+
59
+ market_hash["runners"] = []
60
+
61
+ xml.xpath("//runners").children.each do |xml_runner|
62
+ name = xml_runner.xpath("name").text
63
+ selection_id = xml_runner.xpath("selectionId").text
64
+ market_hash["runners"].push({"selection_id" => selection_id, "name" => name})
65
+ end
66
+
67
+ market_hash
68
+ end
69
+
70
+ def get_market_prices_compressed xml
71
+ prices_hash = {}
72
+ prices = xml.xpath("//marketPrices").text
73
+ # Betfair uses colons as a seperator and escaped colons as a different seperator, grr.
74
+ # [1..-1] removes the first empty string
75
+ prices_data = prices.gsub('\:', 'ECSCOLON')[1..-1].split(":")
76
+
77
+ header_data = prices_data.slice!(0).gsub("ECSCOLON",":").split("~")
78
+
79
+ # TODO - parse removed runners properly
80
+ ["market_id","currency","status","in_play_delay","num_winners","market_info","discount_allowed","market_base_rate","refresh_time","removed_runners","bsp_market"].each_with_index do |field,index|
81
+ prices_hash[field] = header_data.at(index)
82
+ end
83
+
84
+ prices_data.each do |runner|
85
+ runner_hash = {}
86
+ runner_info, lay_prices, back_prices = runner.split("|")
87
+ runner_data = runner_info.split("~")
88
+
89
+ ["selection_id","order_index","total_matched","last_price_matched","handicap","reduction_factor","vacant","asian_line_id","far_sp_price","near_sp_price","actual_sp_price"].each_with_index do |field,index|
90
+ runner_hash[field] = runner_data.at(index)
91
+ end
92
+
93
+ runner_hash["lay_prices"] = []
94
+ lay_prices.split("~").each_slice(4) do |prices|
95
+ runner_hash["lay_prices"].push({"odds" => prices[0], "amount" => prices[1], "type" => prices[2], "depth" => prices[3]})
96
+ end
97
+
98
+ runner_hash["back_prices"] = []
99
+ back_prices.split("~").each_slice(4) do |prices|
100
+ runner_hash["back_prices"].push({"odds" => prices[0], "amount" => prices[1], "type" => prices[2], "depth" => prices[3]})
101
+ end
102
+
103
+ prices_hash[runner_hash["selection_id"]] = runner_hash
104
+ end
105
+ prices_hash
106
+ end
107
+
108
+ def get_market_traded_volume_compressed xml
109
+ traded_volumne_hash = {}
110
+ traded = xml.xpath("//tradedVolume").text
111
+ market_id = xml.xpath("//marketId").text
112
+ currency = xml.xpath("//currencyCode").text
113
+ # Betfair uses colons as a seperator and escaped colons as a different seperator, grr.
114
+ # [1..-1] removes the first empty string
115
+ traded_data = traded.gsub(/\\:/, "ECSCOLON")[1..-1].split(":")
116
+ traded_data.each do |runner|
117
+ # TODO - replace ECSCOLON with :
118
+ runner_hash = {"traded_amounts" => []}
119
+ runner_data = runner.split("|")
120
+ header_data = runner_data.slice!(0).split("~")
121
+ ["selection_id", "asian_line_id", "bsp", "total_bsp_back_matched", "total_bsp_liability_matched"].each_with_index do |field,index|
122
+ runner_hash[field] = header_data.at(index)
123
+ end
124
+ runner_data.each do |traded_amount|
125
+ odds, total_matched = traded_amount.split("~")
126
+ runner_hash["traded_amounts"].push({"odds" => odds, "total_matched" => total_matched})
127
+ end
128
+ traded_volumne_hash[runner_hash["selection_id"]] = runner_hash
129
+ end
130
+ traded_volumne_hash
131
+ end
132
+
133
+ end
134
+
135
+ end
@@ -0,0 +1,29 @@
1
+ require 'haml'
2
+ require 'pathname'
3
+
4
+ module Betfair
5
+
6
+ # Utility class to render a SOAP request from a haml file, embedding data
7
+ # elements as necessary
8
+ class SOAPRenderer
9
+
10
+ def initialize service, soap_name
11
+ base = Pathname.new(__FILE__).realpath.parent
12
+ file = "#{base}/views/#{service}/#{soap_name}.haml"
13
+ unless File.exists?( file )
14
+ $log.error "Cannot find HAML: #{file}" unless $log.nil?
15
+ raise "Cannot find HAML: #{file}"
16
+ end
17
+ @engine = Haml::Engine.new( File.read( file ) ) # this is quite expensive, might be better to keep a hash of renderers
18
+ end
19
+
20
+ def render content
21
+ content.each do |key,value|
22
+ self.instance_variable_set( "@#{key}", value )
23
+ end
24
+ @engine.render( self )
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,23 @@
1
+ %soapenv:Envelope{ "xmlns:soapenv"=> "http://schemas.xmlsoap.org/soap/envelope/", "xmlns:bfex"=>"http://www.betfair.com/publicapi/v5/BFExchangeService/", "xmlns:v5" => 'http://www.betfair.com/publicapi/types/exchange/v5/' }
2
+ %soapenv:Header
3
+ %soapenv:Body
4
+ %bfex:getAllMarkets
5
+ %bfex:request
6
+ %header
7
+ - if @data["client_stamp"]
8
+ %clientStamp= @data["client_stamp"]
9
+ %sessionToken= @data["session_token"]
10
+ - if @data["locale"]
11
+ %locale= @data["locale"]
12
+ - if @data["event_type_ids"]
13
+ %eventTypeIds
14
+ - @data["event_type_ids"].each do |event_id|
15
+ %int=event_id
16
+ - if @data["countries"]
17
+ %countries
18
+ - @data["countries"].each do |cc|
19
+ %Country= cc
20
+ - if @data["from_date"]
21
+ %fromDate= @data["from_date"]
22
+ - if @data["to_date"]
23
+ %toDate= @data["to_date"]
@@ -0,0 +1,12 @@
1
+ %soapenv:Envelope{"xmlns:soapenv" => "http://schemas.xmlsoap.org/soap/envelope/", "xmlns:bfex" => "http://www.betfair.com/publicapi/v5/BFExchangeService/" }
2
+ %soapenv:Header
3
+ %soapenv:Body
4
+ %bfex:getMarket
5
+ %bfex:request
6
+ %header
7
+ - if @data["client_stamp"]
8
+ %clientStamp= @data["client_stamp"]
9
+ %sessionToken= @data["session_token"]
10
+ - if @data["locale"]
11
+ %locale= @data["locale"]
12
+ %marketId= @data["market_id"]
@@ -0,0 +1,12 @@
1
+ %Envelope{ "xmlns:bfex" => 'http://www.betfair.com/publicapi/v5/BFExchangeService/', "xmlns:soapenv" => 'http://schemas.xmlsoap.org/soap/envelope/'}
2
+ %soapenv:Header
3
+ %soapenv:Body
4
+ %bfex:getMarketPricesCompressed
5
+ %bfex:request
6
+ %header
7
+ - if @data["client_stamp"]
8
+ %clientStamp= @data["client_stamp"]
9
+ %sessionToken= @data["session_token"]
10
+ - if @data["currency_code"]
11
+ %currencyCode= @data["currency_code"]
12
+ %marketId= @data["market_id"]
@@ -0,0 +1,12 @@
1
+ %Envelope{ "xmlns:bfex" => 'http://www.betfair.com/publicapi/v5/BFExchangeService/', "xmlns:soapenv" => 'http://schemas.xmlsoap.org/soap/envelope/'}
2
+ %soapenv:Header
3
+ %soapenv:Body
4
+ %bfex:getMarketTradedVolumeCompressed
5
+ %bfex:request
6
+ %header
7
+ - if @data["client_stamp"]
8
+ %clientStamp= @data["client_stamp"]
9
+ %sessionToken= @data["session_token"]
10
+ - if @data["currency_code"]
11
+ %currencyCode= @data["currency_code"]
12
+ %marketId= @data["market_id"]
@@ -0,0 +1,12 @@
1
+ %soapenv:Envelope{"xmlns:soapenv"=>"http://schemas.xmlsoap.org/soap/envelope/", "xmlns:bfg"=> "http://www.betfair.com/publicapi/v3/BFGlobalService/" }
2
+ %soapenv:Header/
3
+ %soapenv:Body
4
+ %bfg:getAllEventTypes
5
+ %bfg:request
6
+ %header
7
+ - if @data["client_stamp"]
8
+ %clientStamp= @data["client_stamp"]
9
+ %sessionToken= @data["session_token"]
10
+ - if @data["locale"]
11
+ %locale= @data["locale"]
12
+
@@ -0,0 +1,11 @@
1
+ %soapenv:Envelope{ "xmlns:soapenv"=> "http://schemas.xmlsoap.org/soap/envelope/", "xmlns:bfg"=> "http://www.betfair.com/publicapi/v3/BFGlobalService/" }
2
+ %soapenv:Header
3
+ %soapenv:Body
4
+ %bfg:login
5
+ %bfg:request
6
+ %ipAddress= @data['ip_address']||0
7
+ %locationId= @data['location_id']||0
8
+ %password= @data['password']
9
+ %productId= @data['product_id']
10
+ %username= @data['username']
11
+ %vendorSoftwareId= @data['vender_software_id']||0
@@ -0,0 +1,9 @@
1
+ %soapenv:Envelope{ "xmlns:soapenv"=> "http://schemas.xmlsoap.org/soap/envelope/", "xmlns:bfg"=> "http://www.betfair.com/publicapi/v3/BFGlobalService/" }
2
+ %soapenv:Header
3
+ %soapenv:Body
4
+ %bfg:retrieveLIMBMessage
5
+ %bfg:request
6
+ %header
7
+ - if @data["client_stamp"]
8
+ %clientStamp= @data["client_stamp"]
9
+ %sessionToken= @data["session_token"]
@@ -0,0 +1,14 @@
1
+ %soapenv:Envelope{ "xmlns:soapenv"=> "http://schemas.xmlsoap.org/soap/envelope/", "xmlns:bfg"=> "http://www.betfair.com/publicapi/v3/BFGlobalService/", "xmlns:v3" => "http://www.betfair.com/publicapi/types/global/v3/" }
2
+ %soapenv:Header
3
+ %soapenv:Body
4
+ %bfg:submitLIMBMessage>
5
+ %bfg:request
6
+ %header
7
+ - if @data["client_stamp"]
8
+ %clientStamp= @data["client_stamp"]
9
+ %sessionToken= @data["session_token"]
10
+ %password= @data["password"]
11
+ %submitPasswordChangeMessage
12
+ %messageId= @data["message_id"]
13
+ %newPassword= @data["new_password"]
14
+ %newPasswordRepeat= @data["new_password"]
data/lib/em-betfair.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'em-betfair/soap_renderer'
2
+ require 'em-betfair/response_parser'
3
+ require 'em-betfair/response'
4
+ require 'em-betfair/betfair_client'