init push - laying out the project

This commit is contained in:
Mike Sutton
2022-11-12 02:27:46 +01:00
commit 14e163a1a5
183 changed files with 20069 additions and 0 deletions

View File

@ -0,0 +1,14 @@
class AccountSyncAndReconciliationJob < ApplicationJob
queue_as :high
def perform(args = {})
ExchangeAccount.active.each do | ea|
am = Integrations::Betfair::AccountManager.new(ea)
bm = Integrations::Betfair::BetManager.new(ea)
puts "Refreshing account balance on '#{ea.id}'"
am.refresh_account_balance
puts "Reconcile open bets on '#{ea.id}'"
bm.check_qualified_bet_outcome(ea.my_bets.open)
end
end
end

View File

@ -0,0 +1,8 @@
class ApplicationJob < ActiveJob::Base
sidekiq_options retry: false
# Automatically retry jobs that encountered a deadlock
# retry_on ActiveRecord::Deadlocked
# Most jobs are safe to ignore if the underlying records are no longer available
# discard_on ActiveJob::DeserializationError
end

View File

@ -0,0 +1,63 @@
class BetPlacementService < ApplicationJob
queue_as :high
def perform(args = {})
# do not proceed if we have already procssed a bet for this tip
bet = args[:bet]
# get a valid betfair instance for the account we are using, halt if not valid.
exchange = Integrations::Betfair::BetManager.new(bet.exchange_account)
return unless exchange
last_step = 'Checking event id'
begin
# check this bet with the exchange and populate the event id if it is missing
unless bet.exchange_event_id
bet.exchange_event_id = exchange.bet_event(bet)
end
bet.placement_attempts += 1
# check the odds are still good at the exchange for that event
last_step = 'Checking odds'
prices_and_stakes = exchange.bet_odds(bet)
prices = prices_and_stakes[:prices]
bet.exchange_odds = prices_and_stakes
bet.outcome = 'expired'
tip_odds = bet.tip_provider_odds.to_f
# use tip odds or get closest match to tip odds offered by the exchange
last_step = 'Determining if odds optimal'
margin = tip_odds * bet.exchange_account.current_stake_strategy[:odds_margin]
max_tip_odds = tip_odds + margin
odds_to_execute_at = prices.min_by { |num| (max_tip_odds - num).abs }
raise 'Cannot determine optimal odds' unless odds_to_execute_at
if odds_to_execute_at.between?(tip_odds, tip_odds + margin)
last_step = 'Determining stake and placing bet'
odds_stake = prices_and_stakes[:stakes][odds_to_execute_at.to_s]
bet.executed_odds = odds_to_execute_at.to_s
# stake will always fill the max available or the limits of our stake management - whichever is the lower.
stake = bet.exchange_account.optimal_stake(bet, exchange.minimum_stake, odds_stake)
raise 'Optimal stake is zero. Not taking bet' if stake.zero?
bet.outcome = 'open'
bet.stake = stake
bet.expected_value = Bet.calculate_expected_value(stake, odds_to_execute_at)
if bet.exchange_account.can_bet?
bet.exchange_bet_id = exchange.place_bet(bet, stake)
end
else
bet.log << '[Bet placement] Tip odds not found in latest prices, nudge too far out'
end
rescue Exception => e
x = "Placement #{bet.placement_attempts}--->Last step: #{last_step}. Error: #{e.message}. Skipping"
bet.log ||= []
bet.log << x
bet.outcome = e.message.include?('PERMISSION_DENIED') ? 'errored' : 'skipped'
ensure
bet.save!
end
end
end

View File

@ -0,0 +1,8 @@
class ClearOldPullsJob < ApplicationJob
queue_as :high
def perform(args = {})
max_hours_to_keep = ENV['MAX_HISTORY_HOURS']&.to_i || 2
TipSourceData.where("created_at < ?", max_hours_to_keep.hours.ago).delete_all
end
end

View File

@ -0,0 +1,10 @@
class ProcessSubscriptionJob < ApplicationJob
queue_as :high
def perform(args = {})
subscription = args[:subscription]
tsd = args[:tsd]
bb = Integrations::Betburger.new()
bb.process_subscription_tips(subscription: subscription, data: tsd)
end
end

View File

@ -0,0 +1,11 @@
class PullEventMarketsJob < ApplicationJob
queue_as :medium
def perform(args = {})
ea = ExchangeAccount.find_by(id: ENV['BETFAIR_HUNTER_ACCOUNT'])
raise 'No Betfair hunter account' unless ea
hunter = Integrations::Betfair::OpportunityHunter.new(ea)
hunter.event_markets_and_selections #refresh the markets to include
end
end

View File

@ -0,0 +1,13 @@
class PullLatestOddsPricesJob < ApplicationJob
queue_as :medium
def perform(args = {})
ea = ExchangeAccount.find_by(id: ENV['BETFAIR_HUNTER_ACCOUNT'])
raise 'No Betfair hunter account' unless ea
hunter = Integrations::Betfair::OpportunityHunter.new(ea)
BetfairEventRunner.runners_for_open_events.each do | runner |
PullRunnerOddsJob.perform_later(hunter: hunter, runner: runner)
end
end
end

View File

@ -0,0 +1,9 @@
class PullRunnerOddsJob < ApplicationJob
queue_as :medium
def perform(args = {})
hunter = params[:oh]
runner = params[:runner]
hunter.runner_odds(runner)
end
end

View File

@ -0,0 +1,16 @@
class PullTipsJob < ApplicationJob
queue_as :high
def perform(args = {})
ta = TipsterAccount.find_by(id: ENV['TIPSTER_ACCOUNT'])
bb = Integrations::Betburger.new(ta)
ta.tip_sources.active_sources.each do |ts|
tsd = bb.pull_and_save_tips(ts)
ts.source_subscriptions.each do |ss|
next unless ss.exchange_account.active?
ProcessSubscriptionJob.perform_later(subscription: ss, tsd: tsd)
end
end
end
end

View File

@ -0,0 +1,13 @@
class PullUpcomingEventsJob < ApplicationJob
queue_as :medium
def perform(args = {})
ea = ExchangeAccount.find_by(id: ENV['BETFAIR_HUNTER_ACCOUNT'])
raise 'No Betfair hunter account' unless ea
hunter = Integrations::Betfair::OpportunityHunter.new(ea)
top_of_hour = Time.now.beginning_of_hour
hunter.events_in_timeframe(from: top_of_hour, to: top_of_hour + 1.hour) #pull events
hunter.event_markets_and_selections #refresh the markets to include
end
end