module Integrations class Betburger include HTTParty attr_reader :access_token URIS = { live: 'https://rest-api-lv.betburger.com/api/v1/valuebets/bot_pro_search', prematch: 'https://rest-api-pr.betburger.com/api/v1/valuebets/bot_pro_search', }.freeze.with_indifferent_access def initialize(tipster_account=nil) super() tipster_account ||= TipsterAccount.find_by(id: ENV['TIPSTER_ACCOUNT']) @access_token = tipster_account.apikey end def pull_and_save_tips(source) url = URIS[source.source_type] return unless url response = self.class.post(url, { body: { per_page: 32, search_filter: source.filters, access_token: @access_token } }) source.tip_source_data.create(data: response) end def process_subscription_tips(subscription:, data:,place_bets: true) return unless subscription tsd = data || subscription.tip_source_data.last # tips already processed return if subscription.subscription_runs.where(tip_source_data_id: tsd.id).exists? json = tsd.data return unless json['total_by_filter'].to_i.positive? percentages = {} vb_refs = json['source']['value_bets'] vb_refs.each do |vb_ref| percentages[vb_ref['bet_id']] = { percent: vb_ref['percent'] } end bet_refs = json['bets'] stats = { non_valuebet: 0, unsupported_exchange: 0, duplicate: 0, processed: 0 } bet_refs.each do |bf| place_this_bet = place_bets unless bf['is_value_bet'] == true stats[:non_valuebet] += 1 next end exchange = exchanges[(bf['bookmaker_id']).to_s] unless exchange stats[:unsupported_exchange] += 1 next end tipster_event_id = bf['event_id'] log = [] bet_id = bf['id'] vb = populate_bet_hash(subscription, bet_id, bf, exchange, log, percentages, tipster_event_id) # on live betting, strictly adhere to max_odds rule. Otherwise bet on all odds to generate learning data. odds_within_range = vb[:tip_provider_odds].to_f.between?( subscription.exchange_account.current_stake_strategy[:min_odds_to_bet], subscription.exchange_account.current_stake_strategy[:max_odds_to_bet]) ev_within_range = vb[:tip_provider_percent].to_f.between?( subscription.exchange_account.current_stake_strategy[:min_ev], subscription.exchange_account.current_stake_strategy[:max_ev]) unless odds_within_range && ev_within_range log << "[Parsing] Tip provider odds not within #{subscription.exchange_account.current_stake_strategy[:min_odds_to_bet]} and #{subscription.exchange_account.current_stake_strategy[:max_odds_to_bet]}" unless odds_within_range log << "[Parsing] Tip provider EV not within #{subscription.exchange_account.current_stake_strategy[:min_ev]} and #{subscription.exchange_account.current_stake_strategy[:max_ev]}" unless ev_within_range vb[:outcome] = 'ignored' place_this_bet = false end vb[:log] = log skip_duplicate_event_check = false duplicates = subscription.exchange_account.my_bets.where(tip_provider_bet_id: bet_id) if duplicates.exists? stats[:duplicate] += 1 if duplicates.retryable_bets.count.positive? bet = duplicates.retryable_bets.last #only supporting 1 duplicate! bet.log = [] bet.update(vb) skip_duplicate_event_check = true else next end end unless skip_duplicate_event_check next if subscription.exchange_account.my_bets.where(tip_provider_event_id: tipster_event_id).exists? && !subscription.exchange_account.allow_multiple_bets_per_event end begin bet ||= Bet.unscoped.create(vb) if bet && place_this_bet && vb[:exchange_market_details] BetPlacementService.perform_later(bet: bet) end rescue Exception => e puts "Something weird happened: #{e.message}" end stats[:processed] += 1 end subscription.subscription_runs.create(tip_source_data_id: tsd.id, log: ["Payload: #{bet_refs.size}. #{stats}"]) end def populate_bet_hash(subscription, bet_id, bf, exchange, log, percentages, tipster_event_id) vb = { tip_provider_id: 'betburger', tip_provider_bet_id: bet_id } vb[:exchange_id] = exchange vb[:exchange_account_id] = subscription.exchange_account.id vb[:tip_provider_event_id] = tipster_event_id vb[:tip_provider_odds] = bf['koef'] # what the tip provider says the odds are from the exchange vb[:exchange_event_id] = bf['bookmaker_event_direct_link'] # may be blank vb[:team1] = bf['team1_name'] vb[:team2] = bf['team2_name'] vb[:period] = periods[bf['period_id'].to_s.to_sym] unless bf['period_id'].blank? vb[:exchange_event_name] = vb[:team1] vb[:exchange_event_name] += " v #{vb[:team2]}" unless vb[:team2].blank? vb[:exchange_event_id] = bf['bookmaker_event_direct_link'] # may be blank vb[:tip_provider_percent] = percentages[bet_id][:percent] # dunno what this is used for tip_market_details = {} tip_market_details[:market] = variations[bf['market_and_bet_type']&.to_s] tip_market_details[:params] = bf['market_and_bet_type_param']&.to_s vb[:tip_provider_market_details] = tip_market_details exchange_market_details = map_exchange_market_details(exchange, tip_market_details, vb[:team1], vb[:team2]) vb[:original_json] = bf if exchange_market_details vb[:exchange_market_details] = exchange_market_details else vb[:outcome] = 'ignored' log << '[Parsing] Unsupported market/selection' end vb end def exchanges @exchanges ||= { '11' => 'betfair' } end def map_exchange_market_details(exchange, tip_market_details, team1, team2) market_mapping = mapped_markets(exchange) return unless market_mapping rtn = market_mapping[tip_market_details[:market]]&.clone return unless rtn swaps = { 'Team1' => team1, 'Team2' => team2, '%s' => tip_market_details[:params]} if tip_market_details[:params] rounded = tip_market_details[:params].to_f.round swaps['%rounded_s'] = "#{rounded.positive? ? '+':''}#{rounded}" if tip_market_details[:params] swaps['%rounded_positive_s'] = "#{rounded.abs}" swaps['%nearest_half_over_s'] = determine_nearest_half(tip_market_details[:params], 'over') if tip_market_details[:params] swaps['%nearest_half_under_s'] = determine_nearest_half(tip_market_details[:params], 'under') if tip_market_details[:params] end swaps.keys.each do |k| rtn[:market] = rtn[:market].sub(k, swaps[k]) rtn[:selection] = rtn[:selection].sub(k, swaps[k]) end if rtn.key?(:handicap) rtn[:handicap] = tip_market_details[:params].to_f end rtn end def determine_nearest_half(line, direction ) line_f = line.to_f - line.to_i return line if line_f == 0.5 line_f = line.to_i + 0.5 line_f -= 1 if direction == 'over' line_f += 1 if direction == 'under' line_f.to_s end def mapped_markets(key) # this is ready for other exchanges @mapped_markets ||= { 'betfair' => betfair_markets } @mapped_markets[key] end def betfair_markets { 'Team1 Win' => { market: 'Match Odds', selection: 'Team1' }, 'Team2 Win' => { market: 'Match Odds', selection: 'Team2' }, 'X' => { market: 'Match Odds', selection: 'The Draw' }, '1' => { market: 'Match Odds', selection: 'Team1' }, '2' => { market: 'Match Odds', selection: 'Team2' }, '1X' => { market: 'Double Chance', selection: 'Home or Draw' }, '12' => { market: 'Double Chance', selection: 'Home or Away' }, 'X2' => { market: 'Double Chance', selection: 'Draw or Away' }, 'Total Over(%s)' => { market: 'Over/Under %nearest_half_over_s Goals', selection: 'Over %nearest_half_over_s Goals' }, 'Total Over(%s) for Team1' => { market: 'Team1 Over/Under %nearest_half_over_s Goals', selection: 'Over %nearest_half_over_s Goals' }, 'Total Over(%s) for Team2' => { market: 'Team2 Over/Under %nearest_half_over_s Goals', selection: 'Over %nearest_half_over_s Goals' }, 'Total Under(%s)' => { market: 'Over/Under %nearest_half_under_s Goals', selection: 'Under %nearest_half_under_s Goals' }, 'Total Under(%s) for Team1' => { market: 'Team1 Over/Under %nearest_half_under_s Goals', selection: 'Under %nearest_half_under_s Goals' }, 'Total Under(%s) for Team2' => { market: 'Team2 Over/Under %nearest_half_under_s Goals', selection: 'Under %nearest_half_under_s Goals' }, 'Asian Handicap1(%s)' => { market: 'Asian Handicap', selection: 'Team1' }, 'Asian Handicap1(0.0)/Draw No Bet' => { market: 'Draw no Bet', selection: 'Team1' }, 'Asian Handicap2(0.0)/Draw No Bet' => { market: 'Draw no Bet', selection: 'Team2' }, 'Asian Handicap2(%s)' => { market: 'Asian Handicap', selection: 'Team2' }, 'European Handicap1(%s)' => { market: 'Team1 +%rounded_positive_s', selection: 'Team1 %rounded_s' }, 'European Handicap2(%s)' => { market: 'Team1 +%rounded_positive_s', selection: 'Team2 %rounded_s' }, 'European HandicapX(%s)' => { market: 'Team1 +%rounded_positive_s', selection: 'Draw' }, 'Both to score' => { market: 'Both teams to score?', selection: 'Yes' }, 'One scoreless' => { market: 'Both teams to score?', selection: 'No' }, 'Only one to score' => { market: 'Both teams to score?', selection: 'No' }, 'Odd' => { market: 'Total Goals Odd/Even', selection: 'Odd' }, 'Even' => { market: 'Total Goals Odd/Even', selection: 'Even' }, 'Mat' => { market: 'Total Goals Odd/Even', selection: 'Even' }, } end def variations @variations ||= { '1' => 'Team1 Win', '2' => 'Team2 Win', '3' => 'Asian Handicap1(0.0)/Draw No Bet', '4' => 'Asian Handicap2(0.0)/Draw No Bet', '5' => 'European Handicap1(%s)', '6' => 'European HandicapX(%s)', '7' => 'European Handicap2(%s)', '8' => 'Both to score', '9' => 'One scoreless', '10' => 'Only one to score', '11' => '1', '12' => 'X', '13' => '2', '14' => '1X', '15' => 'X2', '16' => '12', '17' => 'Asian Handicap1(%s)', '18' => 'Asian Handicap2(%s)', '19' => 'Total Over(%s)', '20' => 'Total Under(%s)', '21' => 'Total Over(%s) for Team1', '22' => 'Total Under(%s) for Team1', '23' => 'Total Over(%s) for Team2', '24' => 'Total Under(%s) for Team2', '25' => 'Odd', '26' => 'Even', '27' => '1 - Yellow Cards', '28' => 'X - Yellow Cards', '29' => '2 - Yellow Cards', '30' => '1X - Yellow Cards', '31' => '12 - Yellow Cards', '32' => 'X2 - Yellow Cards', '33' => 'Asian Handicap1(%s) - Yellow Cards', '34' => 'Asian Handicap2(%s) - Yellow Cards', '35' => 'Total Over(%s) - Yellow Cards', '36' => 'Total Under(%s) - Yellow Cards', '37' => 'Total Under(%s) for Team1 - Yellow Cards', '38' => 'Total Over(%s) for Team1 - Yellow Cards', '39' => 'Total Under(%s) for Team2 - Yellow Cards', '40' => 'Total Over(%s) for Team2 - Yellow Cards', '41' => 'Even - Yellow Cards', '42' => 'Odd - Yellow Cards', '43' => '1 - Corners', '44' => 'X - Corners', '45' => '2 - Corners', '46' => '1X - Corners', '47' => '12 - Corners', '48' => 'X2 - Corners', '49' => 'Asian Handicap1(%s) - Corners', '50' => 'Asian Handicap2(%s) - Corners', '51' => 'Total Over(%s) - Corners', '52' => 'Total Under(%s) - Corners', '53' => 'Total Under(%s) for Team1 - Corners', '54' => 'Total Over(%s) for Team1 - Corners', '55' => 'Total Under(%s) for Team2 - Corners', '56' => 'Total Over(%s) for Team2 - Corners', '57' => 'Odd - Corners', '58' => 'Even - Corners', '63' => 'Red card - yes', '64' => 'No red card', '65' => 'Penalty - yes', '66' => 'No penalty', '67' => 'Score (%s)', '68' => 'Total Over(%s) - Tie Break', '69' => 'Total Under(%s) - Tie Break', '70' => 'Score (%s) - not', '71' => 'Any substitute to score a goal - yes', '72' => 'Any substitute to score a goal - no', '73' => 'Team1 to win by exactly 1 goal - yes', '74' => 'Team1 to win by exactly 1 goal - no', '75' => 'Team2 to win by exactly 1 goal - yes', '76' => 'Team2 to win by exactly 1 goal - no', '77' => 'Team1 to win by exactly 2 goals - yes', '78' => 'Team1 to win by exactly 2 goals - no', '79' => 'Team1 to win by exactly 3 goals - yes', '80' => 'Team1 to win by exactly 3 goals - no', '81' => 'Team2 to win by exactly 2 goals - yes', '82' => 'Team2 to win by exactly 2 goals - no', '83' => 'Team2 to win by exactly 3 goals - yes', '84' => 'Team2 to win by exactly 3 goals - no', '85' => 'Team1 to win to Nil - yes', '86' => 'Team1 to win to Nil - no', '87' => 'Team2 to win to Nil - yes', '88' => 'Team2 to win to Nil - no', '89' => 'Team1 to win either halves - yes', '90' => 'Team1 to win either halves - no', '91' => 'Team2 to win either halves - yes', '92' => 'Team2 to win either halves - no', '93' => 'Draw in either half - yes', '94' => 'Draw in either half - no', '95' => 'Team1 to win in both halves - yes', '96' => 'Team1 to win in both halves - no', '97' => 'Team2 to win in both halves - yes', '98' => 'Team2 to win in both halves - no', '99' => 'Team1 to win and Total Over 2.5 - yes', '100' => 'Team1 to win and Total Over 2.5 - no', '101' => 'Team1 to win and Total Under 2.5 - yes', '102' => 'Team1 to win and Total Under 2.5 - no', '103' => 'Team2 to win and Total Over 2.5 - yes', '104' => 'Team2 to win and Total Over 2.5 - no', '105' => 'Team2 to win and Total Under 2.5 - yes', '106' => 'Team2 to win and Total Under 2.5 - no', '107' => 'Draw in both half - yes', '108' => 'Draw in both half - no', '109' => 'Draw and Total Over 2.5 - yes', '110' => 'Draw and Total Over 2.5 - no', '111' => 'Draw and Total Under 2.5 - yes', '112' => 'Draw and Total Under 2.5 - no', '113' => 'Goals in both halves - yes', '114' => 'Goals in both halves - no', '115' => 'Team1 to score in both halves - yes', '116' => 'Team1 to score in both halves - no', '117' => 'Team2 to score in both halves - yes', '118' => 'Team2 to score in both halves - no', '119' => 'Double - yes', '120' => 'Double - no', '121' => 'Hattrick - yes', '122' => 'Hattrick - no', '123' => 'Own goal - yes', '124' => 'Own goal - no', '125' => 'Both halves > 1.5 goals - yes', '126' => 'Both halves > 1.5 goals - no', '127' => 'Both halves < 1.5 goals - yes', '128' => 'Both halves < 1.5 goals - no', '129' => 'Sets (%s)', '130' => 'Sets (%s) - not', '131' => 'Asian Handicap1(%s) - Sets', '132' => 'Asian Handicap2(%s) - Sets', '133' => 'Total Over(%s) - Sets', '134' => 'Total Under(%s) - Sets', '135' => 'Team1/Team1', '136' => 'Team1/Team1 - no', '137' => 'Team1/Draw', '138' => 'Team1/Draw - no', '139' => 'Team1/Team2', '140' => 'Team1/Team2 - no', '141' => 'Draw/Team1', '142' => 'Draw/Team1 - no', '143' => 'Draw/Draw', '144' => 'Draw/Draw - no', '145' => 'Draw/Team2', '146' => 'Draw/Team2 - no', '147' => 'Team2/Team1', '148' => 'Team2/Team1 - no', '149' => 'Team2/Draw', '150' => 'Team2/Draw - no', '151' => 'Team2/Team2', '152' => 'Team2/Team2 - no', '153' => 'Exact (%s)', '154' => 'Exact (%s) - no', '155' => 'Exact (%s) for Team1', '156' => 'Exact (%s) for Team1 - no', '157' => 'Exact (%s) for Team2', '158' => 'Exact (%s) for Team2 - no', '159' => 'More goals in the 1st half', '160' => 'Equal goals in halves', '161' => 'More goals in the 2nd half', '162' => '1 half most goals (draw no bet)', '163' => '2 half most goals (draw no bet)', '164' => 'Team1 - 1st goal', '165' => 'No goal', '166' => 'Team2 - 1st goal', '167' => 'Team1 - 1st goal (draw no bet)', '168' => 'Team2 - 1st goal (draw no bet)', '169' => 'Team1 - Last goal', '170' => 'No goal', '171' => 'Team2 - Last goal', '172' => 'Team1 - Last goal (draw no bet)', '173' => 'Team2 - Last goal (draw no bet)', '174' => 'Total Over(%s) - Aces', '175' => 'Total Under(%s) - Aces', '176' => 'Total Over(%s) for Team1 - Aces', '177' => 'Total Under(%s) for Team1 - Aces', '178' => 'Total Over(%s) for Team2 - Aces', '179' => 'Total Under(%s) for Team2 - Aces', '180' => 'Total Over(%s) - Double Faults', '181' => 'Total Under(%s) - Double Faults', '182' => 'Total Over(%s) for Team1 - Double Faults', '183' => 'Total Under(%s) for Team1 - Double Faults', '184' => 'Total Over(%s) for Team2 - Double Faults', '185' => 'Total Under(%s) for Team2 - Double Faults', '186' => 'Total Over(%s) for Team1 - 1st Serve', '187' => 'Total Under(%s) for Team1 - 1st Serve', '188' => 'Total Over(%s) for Team2 - 1st Serve', '189' => 'Total Under(%s) for Team2 - 1st Serve', '190' => 'Asian Handicap1(%s) - Aces', '191' => 'Asian Handicap2(%s) - Aces', '192' => 'Asian Handicap1(%s) - Double Faults', '193' => 'Asian Handicap2(%s) - Double Faults', '194' => 'Asian Handicap1(%s) - 1st Serve', '195' => 'Asian Handicap2(%s) - 1st Serve', '196' => 'Player1 - 1st Ace', '197' => 'Player2 - 1st Ace', '198' => 'Player1 - 1st Double Fault', '199' => 'Player2 - 1st Double Fault', '200' => 'Player1 - 1st Break', '201' => 'Player2 - 1st Break', '202' => 'Player1 - 1st Break', '203' => 'No break - 1st Break', '204' => 'Player2 - 1st Break', '205' => '6-0 Set - yes', '206' => '6-0 Set - no', '207' => 'Win From Behind - yes', '208' => 'Win From Behind - no', '209' => 'Exact (%s) - Sets', '210' => 'Exact (%s) - Sets - no', '211' => 'Team1 - 1st corner', '212' => 'No corners', '213' => 'Team2 - 1st corner', '214' => 'Team1 - Last corner', '215' => 'No corners', '216' => 'Team2 - Last corner', '217' => 'Team1 - 1st Yellow Card', '218' => 'No Yellow Card', '219' => 'Team2 - 1st Yellow Card', '220' => 'Team1 - Last Yellow Card', '221' => 'No Yellow Card', '222' => 'Team2 - Last Yellow Card', '223' => 'Team1 - 1st offside', '224' => 'No offsides', '225' => 'Team2 - 1st offside', '226' => 'Team1 - Last offside', '227' => 'No offsides', '228' => 'Team2 - Last offside', '229' => '1st substitution - 1 half', '230' => '1st substitution - intermission', '231' => '1st substitution - 2 half', '232' => '1st goal - 1 half', '233' => 'No goal', '234' => '1st goal - 2 half', '235' => 'Team1 - 1st subs', '236' => 'Team2 - 1st subs', '237' => 'Team1 - Last subs', '238' => 'Team2 - Last subs', '239' => '1 - Shots on goal', '240' => 'X - Shots on goal', '241' => '2 - Shots on goal', '242' => '1X - Shots on goal', '243' => '12 - Shots on goal', '244' => 'X2 - Shots on goal', '245' => 'Asian Handicap1(%s) - Shots on goal', '246' => 'Asian Handicap2(%s) - Shots on goal', '247' => 'Total Over(%s) - Shots on goal', '248' => 'Total Under(%s) - Shots on goal', '249' => 'Total Over(%s) for Team1 - Shots on goal', '250' => 'Total Under(%s) for Team1 - Shots on goal', '251' => 'Total Over(%s) for Team2 - Shots on goal', '252' => 'Total Under(%s) for Team2 - Shots on goal', '253' => 'Odd - Shots on goal', '254' => 'Even - Shots on goal', '255' => '1 - Fouls', '256' => 'X - Fouls', '257' => '2 - Fouls', '258' => '1X - Fouls', '259' => '12 - Fouls', '260' => 'X2 - Fouls', '261' => 'Asian Handicap1(%s) - Fouls', '262' => 'Asian Handicap2(%s) - Fouls', '263' => 'Total Over(%s) - Fouls', '264' => 'Total Under(%s) - Fouls', '265' => 'Total Over(%s) for Team1 - Fouls', '266' => 'Total Under(%s) for Team1 - Fouls', '267' => 'Total Over(%s) for Team2 - Fouls', '268' => 'Total Under(%s) for Team2 - Fouls', '269' => 'Odd - Fouls', '270' => 'Even - Fouls', '271' => '1 - Offsides', '272' => 'X - Offsides', '273' => '2 - Offsides', '274' => '1X - Offsides', '275' => '12 - Offsides', '276' => 'X2 - Offsides', '277' => 'Asian Handicap1(%s) - Offsides', '278' => 'Asian Handicap2(%s) - Offsides', '279' => 'Total Over(%s) - Offsides', '280' => 'Total Under(%s) - Offsides', '281' => 'Total Over(%s) for Team1 - Offsides', '282' => 'Total Under(%s) for Team1 - Offsides', '283' => 'Total Over(%s) for Team2 - Offsides', '284' => 'Total Under(%s) for Team2 - Offsides', '285' => 'Odd - Offsides', '286' => 'Even - Offsides', '287' => 'Team1 to Win From Behind - yes', '288' => 'Team1 to Win From Behind - no', '289' => 'Team2 to Win From Behind - yes', '290' => 'Team2 to Win From Behind - no', '291' => 'Both To Score and W1 - yes', '292' => 'Both To Score and W1 - no', '293' => 'Both To Score and W2 - yes', '294' => 'Both To Score and W2 - no', '295' => 'Both To Score and Draw - yes', '296' => 'Both To Score and Draw - no', '297' => 'Exact (%s) - Added time', '298' => 'Exact (%s) - Added time - no', '299' => 'Total Over(%s) - Added time', '300' => 'Total Under(%s) - Added time', '301' => 'Home No Bet - W2', '302' => 'Home No Bet - Draw', '303' => 'Home No Bet - No Draw', '304' => 'Away No Bet - W1', '305' => 'Away No Bet - Draw', '306' => 'Away No Bet - No Draw', '307' => 'Total Over(%s) - Subs', '308' => 'Total Under(%s) - Subs', '309' => 'Total Over(%s) for Team1 - Subs', '310' => 'Total Under(%s) for Team1 - Subs', '311' => 'Total Over(%s) for Team2 - Subs', '312' => 'Total Under(%s) for Team1 - Subs', '313' => '1 - Ball possession', '314' => 'X - Ball possession', '315' => '2 - Ball possession', '316' => '1X - Ball possession', '317' => '12 - Ball possession', '318' => 'X2 - Ball possession', '319' => 'Asian Handicap1(%s) - Ball possession', '320' => 'Asian Handicap2(%s) - Ball possession', '321' => 'Total Over(%s) for Team1 - Ball possession', '322' => 'Total Under(%s) for Team1 - Ball possession', '323' => 'Total Over(%s) for Team2 - Ball possession', '324' => 'Total Under(%s) for Team2 - Ball possession', '325' => 'Team1 - 1st corner', '326' => 'Team2 - 1st corner', '327' => 'Team1 - Last corner', '328' => 'Team2 - Last corner', '329' => 'Team1 - 1st Yellow Card', '330' => 'Team2 - 1st Yellow Card', '331' => 'Team1 - Last Yellow Card', '332' => 'Team2 - Last Yellow Card', '333' => 'Team1 - 1st offside', '334' => 'Team2 - 1st offside', '335' => 'Team1 - Last offside', '336' => 'Team2 - Last offside', '337' => 'Home No Bet - No W2', '338' => 'Away No Bet - No W1', '339' => '1X and Total Over 2.5 - yes', '340' => '1X and Total Over 2.5 - no', '341' => '1X and Total Under 2.5 - yes', '342' => '1X and Total Under 2.5 - no', '343' => 'X2 and Total Over 2.5 - yes', '344' => 'X2 and Total Over 2.5 - no', '345' => 'X2 and Total Under 2.5 - yes', '346' => 'X2 and Total Under 2.5 - no', '348' => 'Overtime - yes', '351' => 'Overtime - no', '354' => 'Score Draw - yes', '357' => 'Score Draw - no', '360' => 'Race to 2 - Team1', '363' => 'Race to 2 - Team2', '366' => 'Race to 2 - Team1', '369' => 'Race to 2 - neither', '372' => 'Race to 2 - Team2', '375' => 'Race to 3 - Team1', '378' => 'Race to 3 - Team2', '381' => 'Race to 3 - Team1', '384' => 'Race to 3 - neither', '387' => 'Race to 3 - Team2', '390' => 'Race to 4 - Team1', '393' => 'Race to 4 - Team2', '396' => 'Race to 4 - Team1', '399' => 'Race to 4 - neither', '402' => 'Race to 4 - Team2', '405' => 'Race to 5 - Team1', '408' => 'Race to 5 - Team2', '411' => 'Race to 5 - Team1', '414' => 'Race to 5 - neither', '417' => 'Race to 5 - Team2', '420' => 'Race to 10 - Team1', '423' => 'Race to 10 - Team2', '426' => 'Race to 10 - Team1', '429' => 'Race to 10 - neither', '432' => 'Race to 10 - Team2', '435' => 'Race to 15 - Team1', '438' => 'Race to 15 - Team2', '441' => 'Race to 15 - Team1', '444' => 'Race to 15 - neither', '447' => 'Race to 15 - Team2', '450' => 'Race to 20 - Team1', '453' => 'Race to 20 - Team2', '456' => 'Race to 20 - Team1', '459' => 'Race to 20 - neither', '462' => 'Race to 20 - Team2', '467' => 'Team1 - Next goal (draw no bet)', '470' => 'Team2 - Next goal (draw no bet)', '473' => 'Team1 - Next goal', '476' => 'No next goal', '479' => 'Team2 - Next goal', '481' => '1st - yes', '484' => '1st - no', '487' => '1st-3rd - yes', '490' => '1st-3rd - no', '493' => 'W1', '496' => 'W2', '499' => 'TO(%s) - Hits', '502' => 'TU(%s) - Hits', '505' => 'TO(%s) for Team1 - Hits', '508' => 'TU(%s) for Team1 - Hits', '511' => 'TO(%s) for Team2 - Hits', '514' => 'TU(%s) for Team2 - Hits', '517' => 'TO(%s) - Errors', '520' => 'TU(%s) - Errors', '523' => 'TO(%s) - Hits+Errors+Runs', '526' => 'TU(%s) - Hits+Errors+Runs', '529' => 'AH1(%s) - Hits', '532' => 'AH2(%s) - Hits', '535' => '1 - Hits', '538' => 'X - Hits', '541' => '2 - Hits', '546' => 'Team1 Win - Kills', '549' => 'Team2 Win - Kills', '552' => 'Asian Handicap1(%s) - Kills', '555' => 'Asian Handicap2(%s) - Kills', '558' => 'Total Over(%s) - Kills', '561' => 'Total Under(%s) - Kills', '564' => 'Total Over(%s) for Team1 - Kills', '567' => 'Total Under(%s) for Team1 - Kills', '570' => 'Total Over(%s) for Team2 - Kills', '573' => 'Total Under(%s) for Team2 - Kills', '574' => 'W1 - 1st blood', '575' => 'W2 - 1st blood', '576' => 'W1 - 1st tower', '577' => 'W2 - 1st tower', '578' => 'W1 - 1st dragon', '579' => 'W2 - 1st dragon', '580' => 'W1 - 1st baron', '581' => 'W2 - 1st baron', '582' => 'W1 - 1st inhibitor', '583' => 'W2 - 1st inhibitor', '584' => 'W1 - 1st roshan', '585' => 'W2 - 1st roshan', '586' => 'Win pistol rounds - Yes', '587' => 'Win pistol rounds - No', '588' => 'TO(%s) - Duration', '589' => 'TU(%s) - Duration', '590' => 'TO(%s) - Barons', '591' => 'TU(%s) - Barons', '592' => 'TO(%s) - Inhibitors', '593' => 'TU(%s) - Inhibitors', '594' => 'TO(%s) - Towers', '595' => 'TU(%s) - Towers', '596' => 'TO(%s) - Dragons', '597' => 'TU(%s) - Dragons', '598' => 'TO(%s) - Roshans', '599' => 'TU(%s) - Roshans', '600' => 'TO(%s) for Team1 - Sets', '601' => 'TO(%s) for Team1 - Sets', '602' => 'TO(%s) for Team2 - Sets', '603' => 'TO(%s) for Team2 - Sets', '604' => 'W1 - Longest TD', '605' => 'W2 - Longest TD', '606' => 'W1 - Longest FG', '607' => 'W2 - Longest FG', '608' => 'Touchdown - Yes', '609' => 'Touchdown - No', '610' => 'Safety - Yes', '611' => 'Safety - No', '612' => 'First score TD - Yes', '613' => 'First score TD - No', '614' => 'Both teams 10 pts - Yes', '615' => 'Both teams 10 pts - No', '616' => 'Both teams 15 pts - Yes', '617' => 'Both teams 15 pts - No', '618' => 'Both teams 20 pts - Yes', '619' => 'Both teams 20 pts - No', '620' => 'Both teams 25 pts - Yes', '621' => 'Both teams 25 pts - No', '622' => 'Both teams 30 pts - Yes', '623' => 'Both teams 30 pts - No', '624' => 'Both teams 35 pts - Yes', '625' => 'Both teams 35 pts - No', '626' => 'Both teams 40 pts - Yes', '627' => 'Both teams 40 pts - No', '628' => 'Both teams 45 pts - Yes', '629' => 'Both teams 45 pts - No', '630' => 'Both teams 50 pts - Yes', '631' => 'Both teams 50 pts - No', '632' => 'Highest Scoring Quarter - 1st', '633' => 'Highest Scoring Quarter - 2nd', '634' => 'Highest Scoring Quarter - 3rd', '635' => 'Highest Scoring Quarter - 4th', '636' => 'Highest Scoring Quarter - Tie', '637' => 'TO(%s) - Field Goals', '638' => 'TU(%s) - Field Goals', '639' => 'TO(%s) - Touchdowns', '640' => 'TU(%s) - Touchdowns', '641' => 'TO(%s) - Longest TD, distance', '642' => 'TU(%s) - Longest TD, distance', '643' => 'TO(%s) - Longest FG, distance', '644' => 'TU(%s) - Longest FG, distance', '645' => 'TO(%s) for Team1 - Field Goals', '646' => 'TU(%s) for Team1 - Field Goals', '647' => 'TO(%s) for Team2 - Field Goals', '648' => 'TU(%s) for Team2 - Field Goals', '649' => 'TO(%s) for Team1 - Touchdowns', '650' => 'TU(%s) for Team1 - Touchdowns', '651' => 'TO(%s) for Team2 - Touchdowns', '652' => 'TU(%s) for Team2 - Touchdowns', '653' => 'AH1(%s) - Maps', '654' => 'AH2(%s) - Maps', '655' => 'TO(%s) - Maps', '656' => 'TU(%s) - Maps', '657' => 'TO(%s) for Team1 - Maps', '658' => 'TU(%s) for Team1 - Maps', '659' => 'TO(%s) for Team2 - Maps', '660' => 'TU(%s) for Team2 - Maps', '661' => 'Maps (%s)', '662' => 'Maps (%s) - not', '663' => 'Exact (%s) - Maps', '664' => 'Exact (%s) - Maps - no', '665' => 'Win both pistol rounds - Yes', '666' => 'Win both pistol rounds - No', '667' => 'Team1 to win both pistol rounds - Yes', '668' => 'Team1 to win both pistol rounds - No', '669' => 'Team2 to win both pistol rounds - Yes', '670' => 'Team1 to win both pistol rounds - No', '671' => 'Team1 to win at least 1 set - Yes', '672' => 'Team1 to win at least 1 set - No', '673' => 'Team2 to win at least 1 set - Yes', '674' => 'Team1 to win at least 1 set - No', '675' => 'Team1 to win at least 1 map - Yes', '676' => 'Team1 to win at least 1 map - No', '677' => 'Team2 to win at least 1 map - Yes', '678' => 'Team1 to win at least 1 map - No', '679' => 'Both teams kill a dragon - Yes', '680' => 'Both teams kill a dragon - No', '681' => 'Both teams kill a baron - Yes', '682' => 'Both teams kill a baron - No', '683' => 'W1 - 1st Barracks', '684' => 'W2 - 1st Barracks', '685' => 'W1 - 1st Double Kill', '686' => 'W2 - 1st Double Kill', '687' => 'TO(%s) - Barracks', '688' => 'TU(%s) - Barracks', '689' => 'TO(%s) - Double Kills', '690' => 'TU(%s) - Double Kills', '691' => 'AH1(%s) - Barons', '692' => 'AH2(%s) - Barons', '693' => 'AH1(%s) - Dragons', '694' => 'AH2(%s) - Dragons', '695' => 'AH1(%s) - Towers/Turrets', '696' => 'AH2(%s) - Towers/Turrets', '697' => '1 - 3-points', '698' => 'X - 3-points', '699' => '2 - 3-points', '700' => '1 - Rebounds', '701' => 'X - Rebounds', '702' => '2 - Rebounds', '703' => '1 - Assists', '704' => 'X - Assists', '705' => '2 - Assists', '706' => '1X - 3-points', '707' => 'X2 - 3-points', '708' => '12 - 3-points', '709' => '1X - Rebounds', '710' => 'X2 - Rebounds', '711' => '12 - Rebounds', '712' => '1X - Assists', '713' => 'X2 - Assists', '714' => '12 - Assists', '715' => 'AH1(%s) - 3-points', '716' => 'AH2(%s) - 3-points', '717' => 'AH1(%s) - Rebounds', '718' => 'AH2(%s) - Rebounds', '719' => 'AH1(%s) - Assists', '720' => 'AH2(%s) - Assists', '721' => 'TO(%s) - 3-points', '722' => 'TU(%s) - 3-points', '723' => 'TO(%s) - Rebounds', '724' => 'TU(%s) - Rebounds', '725' => 'TO(%s) - Assists', '726' => 'TU(%s) - Assists', '727' => 'TO(%s) for Team1 - 3-points', '728' => 'TU(%s) for Team1 - 3-points', '729' => 'TO(%s) for Team1 - Rebounds', '730' => 'TU(%s) for Team1 - Rebounds', '731' => 'TO(%s) for Team1 - Assists', '732' => 'TU(%s) for Team1 - Assists', '733' => 'TO(%s) for Team2 - 3-points', '734' => 'TU(%s) for Team2 - 3-points', '735' => 'TO(%s) for Team2 - Rebounds', '736' => 'TU(%s) for Team2 - Rebounds', '737' => 'TO(%s) for Team2 - Assists', '738' => 'TU(%s) for Team2 - Assists', '739' => 'W1 - 180s', '740' => 'W2 - 180s', '741' => 'AH1(%s) - 180s', '742' => 'AH2(%s) - 180s', '743' => 'TO(%s) - 180s', '744' => 'TU(%s) - 180s', '745' => '1 - Cards', '746' => 'X - Cards', '747' => '2 - Cards', '748' => '1 - Booking points', '749' => 'X - Booking points', '750' => '2 - Booking points', '751' => '1X - Cards', '752' => 'X2 - Cards', '753' => '12 - Cards', '754' => '1X - Booking points', '755' => 'X2 - Booking points', '756' => '12 - Booking points', '757' => 'AH1(%s) - Cards', '758' => 'AH2(%s) - Cards', '759' => 'AH1(%s) - Booking points', '760' => 'AH2(%s) - Booking points', '761' => 'TO(%s) - Cards', '762' => 'TU(%s) - Cards', '763' => 'TO(%s) - Booking points', '764' => 'TU(%s) - Booking points', '765' => 'TO(%s) for Team1 - Cards', '766' => 'TU(%s) for Team1 - Cards', '767' => 'TO(%s) for Team1 - Booking points', '768' => 'TU(%s) for Team1 - Booking points', '769' => 'TO(%s) for Team2 - Cards', '770' => 'TU(%s) for Team2 - Cards', '771' => 'TO(%s) for Team2 - Booking points', '772' => 'TU(%s) for Team2 - Booking points', '773' => 'Odd - Cards', '774' => 'Even - Cards', '775' => 'Odd - Booking points', '776' => 'Even - Booking points' } end def periods @periods ||= { '1': 'match (pairs)', '2': 'with OT and SO', '3': 'with OT', '4': 'regular time', #match odds '5': '1st', '6': '2nd', '7': '3rd', '8': '4th', '9': '5th', '10': '1st half', #first '13': '2nd half', '14': '1 set, 01 game', '15': '1 set, 02 game', '16': '1 set, 03 game', '17': '1 set, 04 game', '18': '1 set, 05 game', '19': '1 set, 06 game', '20': '1 set, 07 game', '21': '1 set, 08 game', '22': '1 set, 09 game', '23': '1 set, 10 game', '24': '1 set, 11 game', '25': '1 set, 12 game', '26': '1 set, 13 game', '44': '2 set, 01 game', '45': '2 set, 02 game', '46': '2 set, 03 game', '47': '2 set, 04 game', '48': '2 set, 05 game', '49': '2 set, 06 game', '50': '2 set, 07 game', '51': '2 set, 08 game', '52': '2 set, 09 game', '53': '2 set, 10 game', '54': '2 set, 11 game', '55': '2 set, 12 game', '56': '2 set, 13 game', '57': '3 set, 01 game', '58': '3 set, 02 game', '59': '3 set, 03 game', '60': '3 set, 04 game', '61': '3 set, 05 game', '62': '3 set, 06 game', '63': '3 set, 07 game', '64': '3 set, 08 game', '65': '3 set, 09 game', '66': '3 set, 10 game', '67': '3 set, 11 game', '68': '3 set, 12 game', '71': '3 set, 13 game', '76': '6th', '78': '7th', '86': 'regular time', '92': 'regular time', '93': '1st half', '95': 'to qualify', '96': '8th', '97': '9th', '113': '4 set, 01 game', '114': '4 set, 02 game', '115': '4 set, 03 game', '116': '4 set, 04 game', '117': '4 set, 05 game', '118': '4 set, 06 game', '119': '4 set, 07 game', '120': '4 set, 08 game', '121': '4 set, 09 game', '122': '4 set, 10 game', '123': '4 set, 11 game', '124': '4 set, 12 game', '125': '5 set, 01 game', '126': '5 set, 02 game', '127': '5 set, 03 game', '128': '5 set, 04 game', '129': '5 set, 05 game', '130': '5 set, 06 game', '131': '5 set, 07 game', '132': '5 set, 08 game', '133': '5 set, 09 game', '134': '5 set, 10 game', '156': '4 set, 13 game', '159': '5 set, 11 game', '161': '5 set, 12 game', '169': '5 set, 13 game', '223': 'regular time', '243': '1st half', '245': '2nd half', '246': '2nd half', '317': '1st half', '318': '2nd half', '4091': 'regular time', #match odds '4094': '1st half' } end end end