betfair 1.0.3 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +3 -2
- data/README.md +23 -22
- data/betfair.gemspec +4 -3
- data/examples/README.md +3 -0
- data/lib/betfair/api.rb +193 -216
- data/lib/betfair/version.rb +1 -1
- data/spec/betfair/api_spec.rb +75 -68
- data/spec/spec_helper.rb +9 -1
- metadata +54 -25
- data/README_OLD +0 -170
- data/examples/bar.rb +0 -23
- data/examples/foo.rb +0 -42
- data/examples/simplebot.log +0 -4
- data/examples/simplebot/README.md +0 -51
- data/examples/simplebot/daemonize.rb +0 -8
- data/examples/simplebot/monit.conf +0 -6
- data/examples/simplebot/simplebot.rb +0 -170
data/examples/bar.rb
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'betfair'
|
2
|
-
|
3
|
-
bf = Betfair::API.new
|
4
|
-
helpers = Betfair::Helpers.new
|
5
|
-
|
6
|
-
# Test your API limits out
|
7
|
-
|
8
|
-
1.times do |i|
|
9
|
-
session_token = bf.login('username', 'password', 264, 0, 0, nil).to_s
|
10
|
-
puts session_token
|
11
|
-
puts i
|
12
|
-
end
|
13
|
-
|
14
|
-
20.times do |i|
|
15
|
-
puts bf.get_all_markets(session_token, 2, [1,3], nil, nil, '2012-01-23', '2012-01-24').split(':')
|
16
|
-
puts i
|
17
|
-
end
|
18
|
-
|
19
|
-
40.times do |i|
|
20
|
-
details = bf.get_market(session_token, 1, 104678293)
|
21
|
-
prices = bf.get_market_prices_compressed(session_token, 1, 104678293)
|
22
|
-
puts helpers.combine(details, prices)
|
23
|
-
end
|
data/examples/foo.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'betfair'
|
2
|
-
|
3
|
-
bf = Betfair::API.new
|
4
|
-
helpers = Betfair::Helpers.new
|
5
|
-
|
6
|
-
session_token = bf.login('username', 'password', 82, 0, 0, nil).to_s
|
7
|
-
puts session_token
|
8
|
-
puts ""
|
9
|
-
|
10
|
-
# This call just returns back a huge string, markets ar edeliminated by ':', run the split method to convert string to a array
|
11
|
-
markets = bf.get_all_markets(session_token, 1, [1,3], nil, nil, nil, nil).split(':')
|
12
|
-
|
13
|
-
# puts helpers.all_markets(markets)
|
14
|
-
|
15
|
-
# Loop though the markets array
|
16
|
-
markets.each do |market|
|
17
|
-
|
18
|
-
# Once we have a market then the fields with in this are delimnated by '~', run the split method to convert string to a array
|
19
|
-
market = market.split('~')
|
20
|
-
|
21
|
-
market_id = market[0]
|
22
|
-
market_name = market[1].to_s
|
23
|
-
menu_path = market[5]
|
24
|
-
|
25
|
-
# Now lets just look for Match Odds for Tottenham for the English Premier League
|
26
|
-
if market_name == 'Match Odds' and menu_path.include? 'Barclays Premier League' and menu_path.include? 'Tottenham'
|
27
|
-
# Run the API call to get the Market Info
|
28
|
-
details = bf.get_market(session_token, 1, market_id)
|
29
|
-
# Run the API call to get the prices
|
30
|
-
prices = bf.get_market_prices_compressed(session_token, 1, market_id)
|
31
|
-
|
32
|
-
# Pump the data into the helpers
|
33
|
-
bf.get_market(session_token, 1, market_id)
|
34
|
-
puts helpers.market_info(details)
|
35
|
-
puts ""
|
36
|
-
puts helpers.combine(details, prices)
|
37
|
-
puts ""
|
38
|
-
puts helpers.prices_complete(prices)
|
39
|
-
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
data/examples/simplebot.log
DELETED
@@ -1,4 +0,0 @@
|
|
1
|
-
# Logfile created on 2012-03-28 17:07:58 +0800 by logger.rb/25413
|
2
|
-
I, [2012-03-28 17:08:20#2169] INFO -- : username - ["GBR"] - INVALID_USERNAME_OR_PASSWORD - OK - exiting
|
3
|
-
I, [2012-03-28 17:08:53#2309] INFO -- : username - ["GBR"] - INVALID_USERNAME_OR_PASSWORD - OK - exiting
|
4
|
-
I, [2012-03-28 17:09:24#2317] INFO -- : username - ["GBR"] - INVALID_USERNAME_OR_PASSWORD - OK - exiting
|
@@ -1,51 +0,0 @@
|
|
1
|
-
Credits
|
2
|
-
-------
|
3
|
-
Big thanks to wotsisname from the Betfair forums, as per [this post](http://forum.bdp.betfair.com/showthread.php?p=6117#post6117)
|
4
|
-
and [from here](http://bespokebots.com/betfair_bots.php).
|
5
|
-
|
6
|
-
I pretty much copied this directly from his Python bot.
|
7
|
-
|
8
|
-
|
9
|
-
Notes on what it does
|
10
|
-
---------------------
|
11
|
-
|
12
|
-
Logs in to the Betfair UK exchange and monitors the session, logging in again if the session is closed.
|
13
|
-
|
14
|
-
Calls GetAllMarkets and obtains all UK horse racing markets starting in the next 24 hours.
|
15
|
-
|
16
|
-
Filters the markets so we end up with a list of win only, single winner, odds markets with BSP disabled.
|
17
|
-
|
18
|
-
This should leave us with only the UK win markets.
|
19
|
-
|
20
|
-
The strategy checks each market for existing bets.
|
21
|
-
If we have no matched or unmatched bets, the bot will check for any runner available to back at 2.00 or less.
|
22
|
-
If runners are found, it places a LAY bet at the current back price +1 tick/pip to a £2 stake.
|
23
|
-
This places your bet at the front of the queue or gets matched immediately, depending on the back/lay price spread of the market.
|
24
|
-
The bots maximum lay price is 2.01.
|
25
|
-
|
26
|
-
The bot does NOT have a GUI and is intended to be run on a dedicated PC/Mac or a remote VPS.
|
27
|
-
|
28
|
-
Therefore, you should only use this code if you are comfortable with programming in Ruby AND running your scripts from a command line.
|
29
|
-
The API library has been thoroughly tested in a Linux production environment and uptimes exceeding 6 months are easily achieved with suitable error handling.
|
30
|
-
|
31
|
-
|
32
|
-
Disclaimer
|
33
|
-
----------
|
34
|
-
Please note that the bot strategy has NOT been tested beyond basic functionality, so I have no idea whether or not it is profitable long term.
|
35
|
-
The free source code is only intended as an example, so it is up to YOU decide whether or not to use it.
|
36
|
-
Please don't blame me if you lose money using the bot.
|
37
|
-
|
38
|
-
|
39
|
-
Daemonize
|
40
|
-
----------
|
41
|
-
|
42
|
-
`ruby daemonize.rb run` will test the script and output to the logfile location specified
|
43
|
-
|
44
|
-
or
|
45
|
-
|
46
|
-
`ruby daemonize.rb start` will start the script as a daemon and output to the logfile location specified in the background with a pidfile in the root folder
|
47
|
-
|
48
|
-
|
49
|
-
Monit
|
50
|
-
-----
|
51
|
-
See the monit.conf for an example on how to keep this alive on a server.
|
@@ -1,6 +0,0 @@
|
|
1
|
-
check process simplebot
|
2
|
-
with pidfile /home/foo/simplebot/simplebot.pid
|
3
|
-
start program = "/usr/local/rvm/bin/rvm-shell -l -c 'cd /home/foo/simplebot; ruby daemonize.rb start'"
|
4
|
-
stop program = "/usr/local/rvm/bin/rvm-shell -l -c 'cd /home/foo/simplebot; ruby daemonize.rb stop'"
|
5
|
-
if totalmem is greater than 150 MB for 10 cycles then restart # eating up memory?
|
6
|
-
group simplebot
|
@@ -1,170 +0,0 @@
|
|
1
|
-
class SimpleBot
|
2
|
-
|
3
|
-
require 'betfair'
|
4
|
-
require 'date'
|
5
|
-
require 'active_support/core_ext' # Only really need this one to do the easy datetime stuff such as 30.minutes.from_now.utc
|
6
|
-
|
7
|
-
LOG_PATH = '/Users/lukebyrne/Sites/current/betfair/examples/simplebot/simplebot.log' # Absolute path to where you want put your log file
|
8
|
-
|
9
|
-
USERNAME = 'username' # BF Usernmae
|
10
|
-
PASSWORD = 'password' # BF Password
|
11
|
-
PRODUCT_ID = 82 # BF Product ID, Free is 82
|
12
|
-
VENDOR_SOFTWARE_ID = 0
|
13
|
-
LOCATION_ID = 0
|
14
|
-
IP_ADDRESS = nil
|
15
|
-
|
16
|
-
THROTTLE = 3 # How many seconds to wait between checking each market
|
17
|
-
BANDWIDTH_SAVER = 30 # How long to sleep for if no markets are found
|
18
|
-
|
19
|
-
EXCHANGE_ID = 2 # Exchanges you want to hit up 1 for UK, 2 for AUS
|
20
|
-
SPORTS_IDS = [7] # Array of the sports ids you want
|
21
|
-
LOCALE = nil # What coutry are you in? Dont really use this
|
22
|
-
COUNTRIES = ['GBR'] # Array of countries you wish to check for
|
23
|
-
FROM_DATE = nil # This needs to be set within the loop on line 59
|
24
|
-
TO_DATE = nil # This needs to be set within the loop on line 59
|
25
|
-
|
26
|
-
MARKET_NAMES_INGORE = ['To Be Placed'] # Array of markets to ignore
|
27
|
-
MARKET_TYPE = 'O' # Not sure what this is
|
28
|
-
MARKET_STATUS = 'ACTIVE' # Active market types
|
29
|
-
NUMBER_OF_WINNERS = 1 # Only one winner per market
|
30
|
-
BSP_MARKET = true # Starting price market ?
|
31
|
-
IN_PLAY = 0 # 0 means not in play, anything above this means in play
|
32
|
-
|
33
|
-
ODDS = 2.0 # Bet on odds below this
|
34
|
-
BET_SIDE = 'L' # What type of bet, B for back and L for Lay
|
35
|
-
BET_AMOUNT = 2.0 # Note this needs to be a minimum of $5 if you have an AUS account
|
36
|
-
BET_PIP = 1 # Place bet one pip above the ODDS I am checking for, ie this will try and lay 2.0 pounds on odds of 2.01
|
37
|
-
|
38
|
-
BF = Betfair::API.new # Initialize BF API methods
|
39
|
-
HELPERS = Betfair::Helpers.new # Initialize Helper API methods
|
40
|
-
|
41
|
-
LOGGER = Logger.new(LOG_PATH,'daily') # New log file daily
|
42
|
-
original_formatter = Logger::Formatter.new
|
43
|
-
original_formatter.datetime_format = "%Y-%m-%d %H:%M:%S"
|
44
|
-
LOGGER.formatter = proc { |severity, datetime, progname, msg|
|
45
|
-
original_formatter.call(severity, datetime, progname, "#{USERNAME} - #{COUNTRIES} - #{msg}")
|
46
|
-
}
|
47
|
-
|
48
|
-
def run
|
49
|
-
begin
|
50
|
-
token = login # Get our session token
|
51
|
-
if token.success? # Successful login
|
52
|
-
LOGGER.info "Logged in successfully with #{USERNAME}, token returned - #{token}. Fetching Horses from #{COUNTRIES} and looking to lay odds on runners"
|
53
|
-
|
54
|
-
loop do
|
55
|
-
token = BF.keep_alive(token)
|
56
|
-
LOGGER.info("Keep alive - #{token}")
|
57
|
-
|
58
|
-
LOGGER.info 'Fetching markets'
|
59
|
-
markets = BF.get_all_markets(token, EXCHANGE_ID, SPORTS_IDS, LOCALE, COUNTRIES, Time.now.utc, 30.minutes.from_now.utc)
|
60
|
-
|
61
|
-
if markets.is_a?(String) and markets != 'API_ERROR - NO_SESSION' # Markets returned correctly
|
62
|
-
check_markets(token, markets)
|
63
|
-
#token = nil # Set token here to nil to test the token reset below
|
64
|
-
|
65
|
-
elsif markets.is_a?(String) and markets == 'API_ERROR - NO_SESSION' # Session token has expired, try and get a new one
|
66
|
-
token = reset_login
|
67
|
-
|
68
|
-
else # No markets
|
69
|
-
LOGGER.info "No markets found, going to sleep for #{BANDWIDTH_SAVER} seconds"
|
70
|
-
sleep BANDWIDTH_SAVER
|
71
|
-
end
|
72
|
-
|
73
|
-
end # End loop
|
74
|
-
|
75
|
-
else # No login token returned
|
76
|
-
LOGGER.info "#{token.to_s} - exiting"
|
77
|
-
end
|
78
|
-
|
79
|
-
rescue
|
80
|
-
LOGGER.info "Error - SimpleBot.run - #{$!.message}\n(#{$!.class})\n#{$!.backtrace}\n"
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def login
|
85
|
-
BF.login(USERNAME, PASSWORD, PRODUCT_ID, VENDOR_SOFTWARE_ID, LOCATION_ID, IP_ADDRESS)
|
86
|
-
end
|
87
|
-
|
88
|
-
def reset_login
|
89
|
-
token = login
|
90
|
-
if token.success?
|
91
|
-
LOGGER.info "Session token has expired, got a new one - #{token}"
|
92
|
-
else
|
93
|
-
LOGGER.info "Session token has expired, trying to get a new one returned #{token.to_s}"
|
94
|
-
end
|
95
|
-
return token
|
96
|
-
end
|
97
|
-
|
98
|
-
def check_markets(token, markets)
|
99
|
-
markets_hash = []
|
100
|
-
HELPERS.split_markets_string(markets).each do |m|
|
101
|
-
m[:time_to_start] = m[:event_date] - FROM_DATE.to_f # Sort the hash by the time - NEED TO DO THIS
|
102
|
-
markets_hash << m if !m[:market_id].nil? and !MARKET_NAMES_INGORE.include?(m[:market_name]) and MARKET_TYPE == m[:market_type] and MARKET_STATUS == m[:market_status] and NUMBER_OF_WINNERS == m[:number_of_winners] and IN_PLAY == m[:bet_delay] #and BSP_MARKET == m[:bsp_market]
|
103
|
-
end
|
104
|
-
|
105
|
-
if markets_hash.count > 0
|
106
|
-
markets_hash.each { |m| check_runners(token, EXCHANGE_ID, m[:market_id]); sleep THROTTLE; }
|
107
|
-
else
|
108
|
-
LOGGER.info "Markets found but none we are interested in, going to sleep for #{BANDWIDTH_SAVER} seconds"
|
109
|
-
sleep BANDWIDTH_SAVER
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def check_runners(token, exchange_id, market_id)
|
114
|
-
LOGGER.info "#{market_id} - Checking prices for market_id"
|
115
|
-
prices = HELPERS.prices_complete( BF.get_market_prices_compressed(token, exchange_id, market_id) )
|
116
|
-
# Need to recheck whether the market is ACTIVE and not IN_PLAY, this time from what gets returned from prices compressed
|
117
|
-
if MARKET_STATUS == prices[:market_status].to_s and IN_PLAY == prices[:in_play_delay]
|
118
|
-
bets_placed = bets_already_placed(token, exchange_id, market_id)
|
119
|
-
LOGGER.info "#{market_id} - #{bets_placed.count} bets already placed for market_id"
|
120
|
-
|
121
|
-
bets = []
|
122
|
-
prices.each do |k,v|
|
123
|
-
bets << { selection_id: v[:selection_id], b1: v[:b1] } if k.is_a?(Numeric) and !bets_placed.include?(v[:selection_id]) and v[:b1] <= ODDS.to_f
|
124
|
-
end
|
125
|
-
|
126
|
-
if bets.count > 0
|
127
|
-
place_bets(token, exchange_id, market_id, bets)
|
128
|
-
else
|
129
|
-
LOGGER.info "#{market_id} - Bets have already been placed for runners AND/OR no more runners to lay below odds of #{ODDS}"
|
130
|
-
end
|
131
|
-
|
132
|
-
else
|
133
|
-
LOGGER.info "#{market_id} - Is currently either not Active or is In Play"
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
def bets_already_placed(token, exchange_id, market_id)
|
138
|
-
begin
|
139
|
-
LOGGER.info "#{market_id} - Checking existing bets for market_id"
|
140
|
-
bets_placed = []
|
141
|
-
foo = BF.get_mu_bets(token, exchange_id, market_id)
|
142
|
-
if foo != 'NO_RESULTS - OK'
|
143
|
-
foo = [foo] if foo.is_a?(Hash) # If there is only one bet placed on a market then it returns a Hash, not an Array, needs to be an Array so we can loop it
|
144
|
-
foo.each { |bet| bets_placed << bet[:selection_id].to_i }
|
145
|
-
end
|
146
|
-
return bets_placed
|
147
|
-
rescue
|
148
|
-
LOGGER.info "Error - SimpleBot.bets_already_placed - #{$!.message}\n(#{$!.class})\n#{$!.backtrace}\n"
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
def place_bets(token, exchange_id, market_id, bets)
|
153
|
-
begin
|
154
|
-
foo = []
|
155
|
-
bets.each do |bet|
|
156
|
-
price = @helpers.set_betfair_odds(bet[:b1], BET_PIP, false, false)[:prc]
|
157
|
-
|
158
|
-
foo << { market_id: market_id, runner_id: bet[:selection_id], bet_type: BET_SIDE, price: price, size: BET_AMOUNT, asian_line_id: 0,
|
159
|
-
bet_category_type: 'E', bet_peristence_type: 'NONE', bsp_liability: 0 }
|
160
|
-
end
|
161
|
-
bets = BF.place_multiple_bets(token, exchange_id, foo)
|
162
|
-
LOGGER.info "#{market_id} - Placing bets #{bets}"
|
163
|
-
rescue
|
164
|
-
LOGGER.info "Error - SimpleBot.run - #{$!.message}\n(#{$!.class})\n#{$!.backtrace}\n"
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
end
|
169
|
-
SimpleBot.new.run
|
170
|
-
|