2020-02-22 22:56:06 +00:00
using System ;
using System.Collections.Generic ;
using System.Net.Http ;
using System.Net.Http.Headers ;
using System.Text ;
using System.Threading.Tasks ;
2020-02-22 23:56:45 +00:00
using SuccessfulCode.BetfairApi.BettingModels ;
using SuccessfulCode.BetfairApi.BettingModels.Enums ;
2020-02-22 22:56:06 +00:00
2020-02-22 23:56:45 +00:00
namespace SuccessfulCode.BetfairApi
2020-02-22 22:56:06 +00:00
{
public class BettingApiClient
{
private readonly HttpClient _client ;
private Authentication _authentication ;
private const string _endpoint = "https://api.betfair.com/exchange/betting/rest/v1.0/" ;
public BettingApiClient ( Authentication authentication )
{
_client = new HttpClient ();
_authentication = authentication ;
}
private Task < T > ExecuteRequest < T >( string endpoint , object request = null )
{
return _authentication . ExecuteRequest < T >( endpoint , request );
}
/// <summary>
/// Returns a list of Event Types (i.e. Sports) associated with the markets selected by the
/// MarketFilter.
/// </summary>
public async Task < EventTypeResult []> ListEventTypes ( MarketFilter filter , string locale = null )
{
var request = new
{
filter ,
locale
};
var result = await ExecuteRequest < EventTypeResult []>( _endpoint + "listEventTypes/" , request );
return result ;
}
/// <summary>
/// Returns a list of Competitions (i.e., World Cup 2013) associated with the markets selected by the
/// MarketFilter. Currently only Football markets have an associated competition.
/// </summary>
public async Task < CompetitionResult []> ListCompetitions ( MarketFilter filter , string locale = null )
{
var request = new
{
filter ,
locale
};
var result = await ExecuteRequest < CompetitionResult []>( _endpoint + "listCompetitions/" , request );
return result ;
}
/// <summary>
/// Returns a list of time ranges in the granularity specified in the request (i.e. 3PM to 4PM, Aug
/// 14th to Aug 15th) associated with the markets selected by the MarketFilter.
/// </summary>
public async Task < TimeRangeResult []> ListTimeRanges ( MarketFilter filter , TimeGranularity granularity )
{
var request = new
{
filter ,
granularity
};
var result = await ExecuteRequest < TimeRangeResult []>( _endpoint + "listTimeRanges/" , request );
return result ;
}
/// <summary>
/// Returns a list of Events (i.e, Reading vs. Man United) associated with the markets selected by the
/// MarketFilter.
/// </summary>
public async Task < EventResult []> ListEvents ( MarketFilter filter , string locale = null )
{
var request = new
{
filter ,
locale
};
var result = await ExecuteRequest < EventResult []>( _endpoint + "listEvents/" , request );
return result ;
}
/// <summary>
/// Returns a list of market types (i.e. MATCH_ODDS, NEXT_GOAL) associated with the markets selected by
/// the MarketFilter. The market types are always the same, regardless of locale.
/// </summary>
public async Task < MarketTypeResult []> ListMarketTypes ( MarketFilter filter , string locale = null )
{
var request = new
{
filter ,
locale
};
var result = await ExecuteRequest < MarketTypeResult []>( _endpoint + "listMarketTypes/" , request );
return result ;
}
/// <summary>
/// Returns a list of Countries associated with the markets selected by the MarketFilter.
/// </summary>
public async Task < CountryCodeResult []> ListCountries ( MarketFilter filter , string locale = null )
{
var request = new
{
filter ,
locale
};
var result = await ExecuteRequest < CountryCodeResult []>( _endpoint + "listCountries/" , request );
return result ;
}
/// <summary>
/// Returns a list of Venues (i.e. Cheltenham, Ascot) associated with the markets selected by the
/// MarketFilter. Currently, only Horse Racing markets are associated with a Venue.
/// </summary>
public async Task < VenueResult []> ListVenues ( MarketFilter filter , string locale = null )
{
var request = new
{
filter ,
locale
};
var result = await ExecuteRequest < VenueResult []>( _endpoint + "listVenues/" , request );
return result ;
}
/// <summary>
/// Returns a list of information about markets that does not change (or changes very rarely). You use
/// listMarketCatalogue to retrieve the name of the market, the names of selections and other information about
/// markets.
/// </summary>
public async Task < MarketCatalogue []> ListMarketCatalogue ( MarketFilter filter , MarketProjection [] marketProjection = null , int? maxResults = null , MarketSort ? sort = null , string locale = null )
{
var request = new
{
filter ,
marketProjection ,
sort ,
maxResults ,
locale
};
var result = await ExecuteRequest < MarketCatalogue []>( _endpoint + "listMarketCatalogue/" , request );
return result ;
}
/// <summary>
/// Returns a list of dynamic data about markets. Dynamic data includes prices, the status of the
/// market, the status of selections, the traded volume, and the status of any orders you have placed in the
/// market.
/// </summary>
public async Task < MarketBook []> ListMarketBook ( string [] marketIds , PriceProjection priceProjection = null , OrderProjection ? orderProjection = null , MatchProjection ? matchProjection = null , bool? includeOverallPosition = null , bool? partitionMatchedByStrategyRef = null , string [] customerStrategyRefs = null , string currencyCode = null , string locale = null , DateTime ? matchedSince = null , string [] betIds = null )
{
var request = new
{
marketIds ,
priceProjection ,
orderProjection ,
matchProjection ,
includeOverallPosition ,
partitionMatchedByStrategyRef ,
customerStrategyRefs ,
currencyCode ,
locale ,
matchedSince ,
betIds
};
var result = await ExecuteRequest < MarketBook []>( _endpoint + "listMarketBook/" , request );
return result ;
}
/// <summary>
/// Returns a list of dynamic data about a market and a specified runner. Dynamic data includes prices, the status of the
/// market, the status of selections, the traded volume, and the status of any orders you have placed in the
/// market.
/// </summary>
public async Task < MarketBook []> ListRunnerBook ( string marketId , long selectionId , double? handicap = null , PriceProjection priceProjection = null , OrderProjection ? orderProjection = null , MatchProjection ? matchProjection = null , bool? includeOverallPosition = null , bool? partitionMatchedByStrategyRef = null , string [] customerStrategyRefs = null , string currencyCode = null , string locale = null , DateTime ? matchedSince = null , string [] betIds = null )
{
var request = new
{
marketId ,
selectionId ,
handicap ,
priceProjection ,
orderProjection ,
matchProjection ,
includeOverallPosition ,
partitionMatchedByStrategyRef ,
customerStrategyRefs ,
currencyCode ,
locale ,
matchedSince ,
betIds
};
var result = await ExecuteRequest < MarketBook []>( _endpoint + "listRunnerBook/" , request );
return result ;
}
/// <summary>
/// Returns a list of your current orders. Optionally you can filter and sort your current orders using
/// the
/// various parameters, setting none of the parameters will return all of your current orders, up to a maximum
/// of 1000 bets, ordered BY_BET and sorted
/// EARLIEST_TO_LATEST. To retrieve more than 1000 orders, you need to make use of the fromRecord and
/// recordCount parameters.
/// </summary>
public async Task < CurrentOrderSummaryReport > ListCurrentOrders ( string [] betIds = null , string [] marketIds = null , OrderProjection ? orderProjection = null , string [] customerOrderRefs = null , string [] customerStrategyRefs = null , TimeRange placedDateRange = null , TimeRange dateRange = null , OrderBy ? orderBy = null , SortDir ? sortDir = null , int? fromRecord = null , int? recordCount = null )
{
var request = new
{
betIds ,
marketIds ,
orderProjection ,
customerOrderRefs ,
customerStrategyRefs ,
placedDateRange ,
dateRange ,
orderBy ,
sortDir ,
fromRecord ,
recordCount
};
var result = await ExecuteRequest < CurrentOrderSummaryReport >( _endpoint + "listCurrentOrders/" , request );
return result ;
}
/// <summary>
/// Returns a List of bets based on the bet status, ordered by settled date
/// </summary>
public async Task < ClearedOrderSummaryReport > ListClearedOrders ( BetStatus betStatus , string [] eventTypeIds = null , string [] eventIds = null , string [] marketIds = null , RunnerId [] runnerIds = null , string [] betIds = null , string [] customerOrderRefs = null , string [] customerStrategyRefs = null , Side ? side = null , TimeRange settledDateRange = null , GroupBy ? groupBy = null , bool? includeItemDescription = null , string locale = null , int? fromRecord = null , int? recordCount = null )
{
var request = new
{
betStatus ,
eventTypeIds ,
eventIds ,
marketIds ,
runnerIds ,
betIds ,
customerOrderRefs ,
customerStrategyRefs ,
side ,
settledDateRange ,
groupBy ,
includeItemDescription ,
locale ,
fromRecord ,
recordCount
};
var result = await ExecuteRequest < ClearedOrderSummaryReport >( _endpoint + "listClearedOrders/" , request );
return result ;
}
/// <summary>
/// Place new orders into market. LIMIT orders below the minimum bet size are allowed if
/// there is an unmatched bet at the same price in the market. This operation is atomic in that
/// all orders will be placed or none will be placed.
/// </summary>
public async Task < PlaceExecutionReport > PlaceOrders ( string marketId , PlaceInstruction [] instructions , string customerRef = null , MarketVersion marketVersion = null , string customerStrategyRef = null , bool? async = null )
{
var request = new
{
marketId ,
instructions ,
customerRef ,
marketVersion ,
customerStrategyRef ,
async
};
var result = await ExecuteRequest < PlaceExecutionReport >( _endpoint + "placeOrders/" , request );
return result ;
}
/// <summary>
/// Cancel all bets OR cancel all bets on a market OR fully or partially cancel particular orders on a
/// market. Only LIMIT orders an be cancelled or partially cancelled once placed.
/// </summary>
public async Task < CancelExecutionReport > CancelOrders ( string marketId = null , CancelInstruction [] instructions = null , string customerRef = null )
{
var request = new
{
marketId ,
instructions ,
customerRef
};
var result = await ExecuteRequest < CancelExecutionReport >( _endpoint + "cancelOrders/" , request );
return result ;
}
/// <summary>
/// This operation is logically a bulk cancel followed by a bulk place. The cancel is completed first then
/// the new orders are placed. The new orders will be placed atomically in that they will all be placed or none
/// will be placed.
/// In the case where the new orders cannot be placed the cancellations will not be rolled back.
/// See ReplaceInstruction.
/// </summary>
public async Task < ReplaceExecutionReport > ReplaceOrders ( string marketId , ReplaceInstruction [] instructions , string customerRef = null , MarketVersion marketVersion = null , bool? async = null )
{
var request = new
{
marketId ,
instructions ,
customerRef ,
marketVersion ,
async
};
var result = await ExecuteRequest < ReplaceExecutionReport >( _endpoint + "replaceOrders/" , request );
return result ;
}
/// <summary>
/// Update non-exposure changing fields
/// </summary>
public async Task < UpdateExecutionReport > UpdateOrders ( string marketId , UpdateInstruction [] instructions , string customerRef = null )
{
var request = new
{
marketId ,
instructions ,
customerRef
};
var result = await ExecuteRequest < UpdateExecutionReport >( _endpoint + "updateOrders/" , request );
return result ;
}
/// <summary>
/// Retrieve profit and loss for a given list of markets. The values are calculated using matched bets and optionally settled bets.
/// Only odds markets are implemented, markets of other types are silently ignored.
/// </summary>
public async Task < MarketProfitAndLoss []> ListMarketProfitAndLoss ( string [] marketIds , bool? includeSettledBets = null , bool? includeBspBets = null , bool? netOfCommission = null )
{
var request = new
{
marketIds ,
includeSettledBets ,
includeBspBets ,
netOfCommission
};
var result = await ExecuteRequest < MarketProfitAndLoss []>( _endpoint + "listMarketProfitAndLoss/" , request );
return result ;
}
/// <summary>
/// Create/update default exposure limit for market groups of given type.
/// New value and breach action will be immediately applied to existing instances of this type (unless overridden using setExposureLimitForMarketGroup).
/// If default values are overridden for market groups (using setExposureLimitForMarketGroup), overrides will NOT be
/// touched.
/// In order to clear this limit "removeDefaultExposureLimitForMarketGroups" operation should be used. It's not allowed to set default limit to an
/// empty limit (see type ExposureLimit).
/// </summary>
public async Task < string > SetDefaultExposureLimitForMarketGroups ( MarketGroupType marketGroupType , ExposureLimit limit )
{
var request = new
{
marketGroupType ,
limit
};
var result = await ExecuteRequest < string >( _endpoint + "setDefaultExposureLimitForMarketGroups/" , request );
return result ;
}
/// <summary>
/// Create/update exposure limit for a market group.
/// New limit will be applied immediately (even if a default limit exists for this type).
/// The limit will be deleted upon account action (see deleteMarketGroupExposureLimit) or when no active markets
/// remain under market group.
/// It is possible to "invalidate" default limit for a specific group by using a "empty" limit (see type ExposureLimit).
/// Upon successful execution of the request, the effective limit for this group will be the one set by this request (Properties will NOT be inherited from default limit).
/// </summary>
public async Task < string > SetExposureLimitForMarketGroup ( MarketGroup marketGroup , ExposureLimit limit )
{
var request = new
{
marketGroup ,
limit
};
var result = await ExecuteRequest < string >( _endpoint + "setExposureLimitForMarketGroup/" , request );
return result ;
}
/// <summary>
/// Remove default exposure limit for a market group type.
/// This operation will NOT remove/update any market group limits.
/// </summary>
public async Task < string > RemoveDefaultExposureLimitForMarketGroups ( MarketGroupType marketGroupType )
{
var request = new
{
marketGroupType
};
var result = await ExecuteRequest < string >( _endpoint + "removeDefaultExposureLimitForMarketGroups/" , request );
return result ;
}
/// <summary>
/// Delete exposure limit for a market group.
/// If a default exposure limit exist for market type, it takes effect immediately.
/// </summary>
public async Task < string > RemoveExposureLimitForMarketGroup ( MarketGroup marketGroup )
{
var request = new
{
marketGroup
};
var result = await ExecuteRequest < string >( _endpoint + "removeExposureLimitForMarketGroup/" , request );
return result ;
}
/// <summary>
/// Response to this request returns default group limit and group limits grouped by type.
/// If marketGroupTypeFilter is not populated values for all types are returned.
/// The response will always contain the default limit. It is possible to control which groups to return using marketGroupsFilter parameter.
/// If marketGroupsFilter is not set all group limits are returned. If an emtpy list is passed only default limit(s) is returned.
/// When marketGroupTypeFilter and marketGroupsFilter used together, all groups in marketGroupsFilter are required to be of same type (type used in marketGroupTypeFilter).
/// </summary>
public async Task < ExposureLimitsForMarketGroups []> ListExposureLimitsForMarketGroups ( MarketGroupType ? marketGroupTypeFilter = null , MarketGroup [] marketGroupFilter = null )
{
var request = new
{
marketGroupTypeFilter ,
marketGroupFilter
};
var result = await ExecuteRequest < ExposureLimitsForMarketGroups []>( _endpoint + "listExposureLimitsForMarketGroups/" , request );
return result ;
}
/// <summary>
/// Unblock a market group after it has been blocked due to the breach of a previously set exposure limit.
/// </summary>
public async Task < string > UnblockMarketGroup ( MarketGroup marketGroup )
{
var request = new
{
marketGroup
};
var result = await ExecuteRequest < string >( _endpoint + "unblockMarketGroup/" , request );
return result ;
}
/// <summary>
/// Retrieves events from exposure reuse enabled events list. To edit this list use
/// addExposureReuseEnabledEvents and removeExposureReuseEnabledEvents operations.
/// </summary>
public async Task < long []> GetExposureReuseEnabledEvents ()
{
var result = await ExecuteRequest < long []>( _endpoint + "getExposureReuseEnabledEvents/" );
return result ;
}
/// <summary>
/// Enables events for exposure reuse by appending them to the current list of events already enabled.
/// </summary>
public async Task < string > AddExposureReuseEnabledEvents ( long [] eventIds )
{
var request = new
{
eventIds
};
var result = await ExecuteRequest < string >( _endpoint + "addExposureReuseEnabledEvents/" , request );
return result ;
}
/// <summary>
/// Removes events from exposure reuse enabled events list.
/// </summary>
public async Task < string > RemoveExposureReuseEnabledEvents ( long [] eventIds )
{
var request = new
{
eventIds
};
var result = await ExecuteRequest < string >( _endpoint + "removeExposureReuseEnabledEvents/" , request );
return result ;
}
}
}