481 lines
21 KiB
C#
481 lines
21 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Net.Http;
|
|
using System.Net.Http.Headers;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using SuccessfulCode.BetfairApi.BettingModels;
|
|
using SuccessfulCode.BetfairApi.BettingModels.Enums;
|
|
|
|
namespace SuccessfulCode.BetfairApi
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
} |