uk.co.onehp.trickle.services.betfair.BetfairServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for uk.co.onehp.trickle.services.betfair.BetfairServiceImpl.java

Source

/*
 * Betfair Trickle. Automatic bet placement application. Copyright (C) 2011
 * Thomas Inman. This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version. This program is distributed in the hope that it
 * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details. You should have received a copy of the GNU
 * General Public License along with this program; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package uk.co.onehp.trickle.services.betfair;

import java.math.BigDecimal;
import java.util.Map;

import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.spi.BrowsableEndpoint;
import org.joda.time.LocalDateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import uk.co.onehp.trickle.domain.Bet;
import uk.co.onehp.trickle.domain.BetLog;
import uk.co.onehp.trickle.domain.BetType;
import uk.co.onehp.trickle.domain.BettingAspect;
import uk.co.onehp.trickle.domain.Pricing;
import uk.co.onehp.trickle.domain.Strategy;
import uk.co.onehp.trickle.services.domain.DomainService;
import uk.co.onehp.trickle.services.session.SessionService;
import uk.co.onehp.trickle.util.BettingUtil;

import com.betfair.publicapi.types.exchange.v5.ArrayOfPlaceBets;
import com.betfair.publicapi.types.exchange.v5.BetCategoryTypeEnum;
import com.betfair.publicapi.types.exchange.v5.BetPersistenceTypeEnum;
import com.betfair.publicapi.types.exchange.v5.BetTypeEnum;
import com.betfair.publicapi.types.exchange.v5.GetMarketPricesReq;
import com.betfair.publicapi.types.exchange.v5.GetMarketReq;
import com.betfair.publicapi.types.exchange.v5.PlaceBets;
import com.betfair.publicapi.types.exchange.v5.PlaceBetsReq;
import com.betfair.publicapi.types.global.v3.GetEventsReq;
import com.betfair.publicapi.types.global.v3.LoginReq;
import com.betfair.publicapi.types.global.v3.ViewProfileReq;
import com.google.common.collect.Maps;
import com.google.gson.Gson;

@Service("betfairService")
public class BetfairServiceImpl implements BetfairService {

    @Value("${bfusername}")
    private String username;

    @Value("${bfpassword}")
    private String password;

    @Value("${sessionTimeout}")
    private int sessionTimeout;

    @Value("${ukMarketId}")
    private int ukMarketId;

    @Autowired
    private CamelContext camelContext;

    @Autowired
    private ProducerTemplate producerTemplate;

    @Autowired
    private SessionService sessionService;

    @Autowired
    private DomainService domainService;

    @Override
    @Transactional
    public void login() {
        if (((BrowsableEndpoint) this.camelContext.getEndpoint("jms:login")).getExchanges().size() == 0) {
            LoginReq loginReq = new LoginReq();
            loginReq.setUsername(this.username);
            loginReq.setPassword(this.password);
            sendRequest(loginReq);
        }
    }

    @Override
    @Transactional
    public void viewProfile() {
        ViewProfileReq viewProfileReq = new ViewProfileReq();
        sendRequest(viewProfileReq);
    }

    @Override
    @Transactional
    public void getMeeting(int meetingId) {
        GetEventsReq getEventsReq = new GetEventsReq();
        getEventsReq.setEventParentId(meetingId);
        sendRequest(getEventsReq);
    }

    @Override
    @Transactional
    public void getUkMarket() {
        GetEventsReq getEventsReq = new GetEventsReq();
        getEventsReq.setEventParentId(this.ukMarketId);
        sendRequest(getEventsReq);
    }

    @Override
    @Transactional
    public void getRace(int raceId) {
        GetMarketReq getMarketInfoReq = new GetMarketReq();
        getMarketInfoReq.setMarketId(raceId);
        sendRequest(getMarketInfoReq);
    }

    @Override
    @Transactional
    public void getRacePrices(int raceId) {
        GetMarketPricesReq getMarketPricesReq = new GetMarketPricesReq();
        getMarketPricesReq.setMarketId(raceId);
        sendRequest(getMarketPricesReq);
    }

    @Override
    @Transactional
    public void placeBet(Bet bet) {
        PlaceBetsReq placeBetsReq = new PlaceBetsReq();
        placeBetsReq.setBets(new ArrayOfPlaceBets());
        //if price falls within range
        //if chasing
        //place entire amount at chased price, market on close
        //else
        //place as much as possible at highest price, market on close
        //place remainder at SP limit on close
        //else
        //place at SP limit on close
        Strategy strategy = bet.getStrategy();
        BigDecimal liability = strategy.getLiability().divide(new BigDecimal(bet.getNumberOfSplits()),
                BigDecimal.ROUND_HALF_UP);
        Pricing bestPricing = BettingUtil.bestPrice(bet.getHorse().getPrices(), strategy.getAspect());
        if (bestPricing.getPrice().compareTo(strategy.getMaxOdds()) <= 0
                && bestPricing.getPrice().compareTo(strategy.getMinOdds()) >= 0) {
            if (strategy.getChasePriceByTick() == 0) {
                if (bestPricing.getAmountAvailable().compareTo(liability) >= 0) {
                    placeBetsReq.getBets().getPlaceBets()
                            .add(createMOCExchangeBet(bet, liability, bestPricing.getPrice()));
                } else {
                    placeBetsReq.getBets().getPlaceBets().add(
                            createMOCExchangeBet(bet, bestPricing.getAmountAvailable(), bestPricing.getPrice()));
                    placeBetsReq.getBets().getPlaceBets()
                            .add(createLimitedSPBet(bet, liability.subtract(bestPricing.getAmountAvailable())));
                }
            } else {
                placeBetsReq.getBets().getPlaceBets()
                        .add(createMOCExchangeBet(bet, liability, BettingUtil.findChasePrice(bestPricing.getPrice(),
                                strategy.getChasePriceByTick(), strategy.getAspect())));
            }
        } else {
            placeBetsReq.getBets().getPlaceBets().add(createLimitedSPBet(bet, liability));
        }
        sendRequest(placeBetsReq);
    }

    private PlaceBets createLimitedSPBet(Bet bet, BigDecimal liability) {
        BigDecimal price = (bet.getStrategy().getAspect() == BettingAspect.BACK ? bet.getStrategy().getMinOdds()
                : bet.getStrategy().getMaxOdds());
        bet.addLog(new BetLog(new LocalDateTime(), liability, price, BetType.LIMITED_SP));
        this.domainService.updateBet(bet);
        PlaceBets placeBets = new PlaceBets();
        placeBets.setBetType(bet.getStrategy().getAspect() == BettingAspect.BACK ? BetTypeEnum.B : BetTypeEnum.L);
        placeBets.setBetCategoryType(BetCategoryTypeEnum.L);
        placeBets.setBetPersistenceType(BetPersistenceTypeEnum.NONE);
        placeBets.setMarketId(bet.getHorse().getRaceId());
        placeBets.setSelectionId(bet.getHorse().getRunnerId());
        placeBets.setBspLiability(liability.doubleValue());
        placeBets.setSize(bet.getStrategy().getAspect() == BettingAspect.BACK ? liability.doubleValue()
                : BettingUtil.libilityToStake(liability, price).doubleValue());
        placeBets.setPrice(price.doubleValue());
        return placeBets;
    }

    private PlaceBets createMOCExchangeBet(Bet bet, BigDecimal liability, BigDecimal price) {
        bet.addLog(new BetLog(new LocalDateTime(), liability, price, BetType.MOC_EXCHANGE));
        this.domainService.updateBet(bet);
        PlaceBets placeBets = new PlaceBets();
        placeBets.setBetType(bet.getStrategy().getAspect() == BettingAspect.BACK ? BetTypeEnum.B : BetTypeEnum.L);
        placeBets.setBetCategoryType(BetCategoryTypeEnum.E);
        placeBets.setBetPersistenceType(BetPersistenceTypeEnum.SP);
        placeBets.setMarketId(bet.getHorse().getRaceId());
        placeBets.setSelectionId(bet.getHorse().getRunnerId());
        placeBets.setSize(bet.getStrategy().getAspect() == BettingAspect.BACK ? liability.doubleValue()
                : BettingUtil.libilityToStake(liability, price).doubleValue());
        placeBets.setPrice(price.doubleValue());
        //Workaround for known bug in betfair
        placeBets.setBspLiability(0.0);
        return placeBets;
    }

    private void sendRequest(Object body) {
        if (body.getClass() != LoginReq.class) {
            if (this.sessionService.getGlobalSessionTokenUpdateDateTime().plusSeconds(this.sessionTimeout)
                    .isBefore(new LocalDateTime())) {
                login();
            }
        }
        final Map<String, Object> headers = Maps.newHashMap();
        headers.put("requestType", body.getClass().toString());
        this.producerTemplate.sendBodyAndHeaders("jms:betfair", new Gson().toJson(body), headers);
    }
}