init push - laying out the project
This commit is contained in:
14
portal/app/jobs/account_sync_and_reconciliation_job.rb
Normal file
14
portal/app/jobs/account_sync_and_reconciliation_job.rb
Normal 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
|
8
portal/app/jobs/application_job.rb
Normal file
8
portal/app/jobs/application_job.rb
Normal 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
|
63
portal/app/jobs/bet_placement_service.rb
Normal file
63
portal/app/jobs/bet_placement_service.rb
Normal 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
|
8
portal/app/jobs/clear_old_pulls_job.rb
Normal file
8
portal/app/jobs/clear_old_pulls_job.rb
Normal 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
|
10
portal/app/jobs/process_subscription_job.rb
Normal file
10
portal/app/jobs/process_subscription_job.rb
Normal 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
|
11
portal/app/jobs/pull_event_markets_job.rb
Normal file
11
portal/app/jobs/pull_event_markets_job.rb
Normal 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
|
13
portal/app/jobs/pull_latest_odds_prices_job.rb
Normal file
13
portal/app/jobs/pull_latest_odds_prices_job.rb
Normal 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
|
9
portal/app/jobs/pull_runner_odds_job.rb
Normal file
9
portal/app/jobs/pull_runner_odds_job.rb
Normal 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
|
16
portal/app/jobs/pull_tips_job.rb
Normal file
16
portal/app/jobs/pull_tips_job.rb
Normal 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
|
13
portal/app/jobs/pull_upcoming_events_job.rb
Normal file
13
portal/app/jobs/pull_upcoming_events_job.rb
Normal 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
|
Reference in New Issue
Block a user