Can anyone give me some pointers on the best way to parse getCompleteMarketPricesCompressed. Want to rewrite my scripts to use it as it includes all the info , some sort of future proofing in case I need the extra data. Bit of a pain though as the prices aren't delimited in anyway and just set as one long string limited by ~. I guess it's just a case of stripping it in chunks of fives ? Any pointers especially for php would be happily received :)
Also wondered if anyone else is getting errors when calling it as I seem to get quite a few API_ERROR's returned with no further ifo and I'm not exceeding limts etc
Ignore the error stuff just added some checking t inclde the header error code and it may have been exceeding the throttle, guess I had some other scripts running at the same time but they were linked to another account.
Are you already doing GetMarketPricesCompressed? It's not so different
I can post some C# code that does it and you could strip the logic out - let me know if that's useful or not...
Yes using gmpc on my bots at the moment, that's easy enough to parse for me as they just show the top 3 back and lays so everything is constant and i just split and explode it knowing the best back/lays will always be in the same part of the array whereas with the getcomplete it's showing all prices so not regular.
If you could post the code it'd be great as I'm sure I should be abe to at least recode the strategy to php
Thanks
Ah good point - not sure I've tested it on empty market - I've coded it but not used in anger as still using GMPC for now - let me give it a test first and then post
Python if it helps:-
http://code.google.com/p/pythonbetfairlibrary/source/browse/trunk/exchange.py
Line 509+
bmsleight, thanks very much for that, I'm having a look at it now. Thanks heaps.
Seems to work ok on empty markets - here it is - make of it what you will!
TraderMarketPrice price = new TraderMarketPrice(true);
switch (response.errorCode)
{
case GetCompleteMarketPricesErrorEnum.OK:
sLogger.DebugFormat("Processing Price for {0} {1}", market.MenuPath, market.Name);
mGlobalSession.SessionToken = response.header.sessionToken;
string token;
Tokenizer tokenizer = new Tokenizer(response.completeMarketPrices);
char[] delimiters = new char[] { ':', '~', '|' };
while (tokenizer.GetNextToken(delimiters, out token))
{
switch (tokenizer.TokenNo)
{
case 0:
{
price.MarketId = Int32.Parse(token);
break;
}
case 1:
{
price.BetDelay = Int32.Parse(token);
break;
}
case 2:
{
//Removed Runners
ProcessRemovedRunners(price, token);
//Runners and price
char[] runnersDelimiters = new char[] { ':' };
string runnersToken;
while (tokenizer.GetNextToken(runnersDelimiters, out runnersToken))
{
string[] runnerFields = runnersToken.Split('|');
string runnerInfo = runnerFields[0];
string completePrices = runnerFields[1];
TraderRunnerPrices runnerPrices = ProcessGCMPCRunnerInfo(runnerInfo, price.CurrencyCode);
// TODO not that we have this data from GCMPC...
runnerPrices.LastRefresh = price.LastRefresh;
ProcessCompletePrices(completePrices, runnerPrices.LayPrices, runnerPrices.BackPrices, price.CurrencyCode);
price.RunnerPrices.Add(runnerPrices);
}
break;
}
}
}
break;// TODO make sure I have got back and lay the right way round!!!
private void ProcessCompletePrices(string priceData, IList<TraderPrice> layPrices, IList<TraderPrice> backPrices, string currency)
{
string[] prices = priceData.Split('~');
for (int i = 0; i < prices.Length - 1; i += 5)
{
double odds = Double.Parse(prices[i]);
// TODO - need to sort out the currency...
double backAmountAvailable = mGlobalSession.ConvertToBase(Double.Parse(prices[i + 1]), currency);
double layAmountAvailable = mGlobalSession.ConvertToBase(Double.Parse(prices[i + 2]), currency);
// TODO get the BSP data too
if (backAmountAvailable > 0)
{
TraderPrice price = new TraderPrice();
price.Odds = odds;
price.AmountAvailable = backAmountAvailable;
// price.Depth = ???? TODO cunning handling here??
layPrices.Add(price);
}
if (layAmountAvailable > 0)
{
TraderPrice price = new TraderPrice();
price.Odds = odds;
price.AmountAvailable = layAmountAvailable;
// price.Depth = ???? TODO cunning handling here??
backPrices.Add(price);
}
}
}
[code}
private TraderRunnerPrices ProcessGCMPCRunnerInfo(string runnerInfo, string currency)
{
string token;
Tokenizer tokenizer = new Tokenizer(runnerInfo);
char[] delimiters = new char[] { '~' };
TraderRunnerPrices runnerPrices = new TraderRunnerPrices();
while (tokenizer.GetNextToken(delimiters, out token))
{
switch (tokenizer.TokenNo)
{
case 0:
{
runnerPrices.Id = Int32.Parse(token);
break;
}
case 1:
{
runnerPrices.Index = Int32.Parse(token);
break;
}
case 2:
{
runnerPrices.TotalAmountMatched = mGlobalSession.ConvertToBase(Double.Parse(token), currency);
break;
}
case 3:
{
if (token != string.Empty)
{
runnerPrices.LastPriceMatched = Double.Parse(token);
}
break;
}
case 4:
{
if (token != string.Empty)
{
runnerPrices.Handicap = Double.Parse(token);
}
break;
}
case 5:
{
if (token != string.Empty)
{
runnerPrices.ReductionFactor = Double.Parse(token);
}
break;
}
case 6:
{
if (token != string.Empty)
{
runnerPrices.Vacant = Boolean.Parse(token);
}
break;
}
case 7:
{
runnerPrices.AsianLineId = Int32.Parse(token);
break;
}
case 8:
{
if (token != string.Empty)
{
if (token.Equals("NaN") || token.Equals("Infinity"))
{
runnerPrices.FarSPPrice = 0;
}
else
{
runnerPrices.FarSPPrice = Double.Parse(token);
}
}
break;
}
case 9:
{
if (token != string.Empty)
{
if (token.Equals("NaN") || token.Equals("Infinity"))
{
runnerPrices.NearSPPrice = 0;
}
else
{
runnerPrices.NearSPPrice = Double.Parse(token);
}
}
break;
}
case 10:
{
if (token != string.Empty)
{
runnerPrices.ActualSPPrice = Double.Parse(token);
}
break;
}
}
}
return runnerPrices;
}
[/code]
private static void ProcessRemovedRunners(TraderMarketPrice price, string token)
{
if (token.Length > 0)
{
string[] removedRunners = token.Split(';');
foreach (string removedRunner in removedRunners)
{
if (removedRunner != string.Empty)
{
string[] rrFields = removedRunner.Split(',');
TraderRemovedRunner rr = new TraderRemovedRunner();
rr.Name = rrFields[0];
string[] dateFields = rrFields[1].Split('.');
int hours = Int32.Parse(dateFields[0]);
int mins = Int32.Parse(dateFields[1]);
rr.RemovedDate = new DateTime(1900, 01, 01, hours, mins, 0);
rr.AdjustmentFactor = Double.Parse(rrFields[2]);
price.RemovedRunners.Add(rr);
}
}
}
}oops sorry for the formatting problem - still you get the idea
Python if it helps:- http://code.google.com/p/pythonbetfairlibrary/source/browse/trunk/exchange.pyLine 509+
I've never learned python, but it's quite compelling when it looks like that - I might have to have a go!
I have only just started to learn Python. Got to love it is so well,
nice
.
I'm impressed.
peteb, thanks for that code, I'm such a newb at programming that I find it tricky to follow the logic of most other languages, but that looks close enough to Java that I can puzzle it out.
inksmithy, note that is for GCMPC.
If it's useful, I can post the equivalent GMPC code this evening.
cheers,
Alan
Thanks for the input lads, managed to find an array command within php to sort it.
$final=array_chunk(explode('~',$runnerinfo), 5);
Don't think I could migrate to C# Pete , some of my bots use less code than your routine :)
Er yep comparing the end result, C# doesn't look great... but it does kind of write itself as you think, so it's not so bad - coming from C++ it's fantastic!
Ok this is the GMPC code - probably looks even worse!
TraderMarketPrice price = new TraderMarketPrice(true);
switch (response.errorCode)
{
case GetMarketPricesErrorEnum.OK:
sLogger.DebugFormat("Processing Price for {0} {1}", market.MenuPath, market.Name);
mGlobalSession.SessionToken = response.header.sessionToken;
string token;
Tokenizer tokenizer = new Tokenizer(response.marketPrices);
char[] delimiters = new char[] {':', '~', '|'};
while (tokenizer.GetNextToken(delimiters, out token))
{
switch (tokenizer.TokenNo)
{
case 0:
{
price.MarketId = Int32.Parse(token);
break;
}
case 1:
{
price.CurrencyCode = token;
break;
}
case 2:
{
price.Status = ParseMarketStatus(tokenizer.Data, token);
break;
}
case 3:
{
price.BetDelay = Int32.Parse(token);
break;
}
case 4:
{
price.NumberOfWinners = Int32.Parse(token);
break;
}
case 5:
{
price.MarketInformation = token;
break;
}
case 6:
{
price.DiscountAllowed = Boolean.Parse(token);
break;
}
case 7:
{
price.MarketBaseRate = Double.Parse(token);
break;
}
case 8:
{
double msSince1Jan1970 = Double.Parse(token);
price.LastRefresh = DateTime.SpecifyKind(mGlobalSession.FirstJan1970.AddMilliseconds(msSince1Jan1970), DateTimeKind.Utc);
break;
}
case 9:
{
//Removed Runners
ProcessRemovedRunners(price, token);
break;
}
case 10:
{
// BSPMarket
switch (token)
{
case "Y":
case "y":
{
price.BSPMarket = true;
break;
}
case "N":
case "n":
{
price.BSPMarket = false;
break;
}
}
//Runners and price
char[] runnersDelimiters = new char[] {':'};
string runnersToken;
while (tokenizer.GetNextToken(runnersDelimiters, out runnersToken))
{
string[] runnerFields = runnersToken.Split('|');
string runnerInfo = runnerFields[0];
string layPrices = runnerFields[1];
string backPrices = runnerFields[2];
TraderRunnerPrices runnerPrices = ProcessGMPCRunnerInfo(runnerInfo, price.CurrencyCode);
runnerPrices.LastRefresh = price.LastRefresh;
ProcessPrices(layPrices, runnerPrices.LayPrices, price.CurrencyCode);
ProcessPrices(backPrices, runnerPrices.BackPrices, price.CurrencyCode);
price.RunnerPrices.Add(runnerPrices);
}
break;
}
}
}
break;private void ProcessPrices(string priceData, IList<TraderPrice> traderPrices, string currency)
{
string[] prices = priceData.Split('~');
for (int i = 0; i < prices.Length - 1; i += 4)
{
TraderPrice price = new TraderPrice();
price.Odds = Double.Parse(prices[i]);
price.AmountAvailable = mGlobalSession.ConvertToBase(Double.Parse(prices[i + 1]), currency);
price.Depth = Int32.Parse(prices[i + 3]);
traderPrices.Add(price);
}
}private TraderRunnerPrices ProcessGMPCRunnerInfo(string runnerInfo, string currency)
{
string token;
Tokenizer tokenizer = new Tokenizer(runnerInfo);
char[] delimiters = new char[] {'~'};
TraderRunnerPrices runnerPrices = new TraderRunnerPrices();
while (tokenizer.GetNextToken(delimiters, out token))
{
switch (tokenizer.TokenNo)
{
case 0:
{
runnerPrices.Id = Int32.Parse(token);
break;
}
case 1:
{
runnerPrices.Index = Int32.Parse(token);
break;
}
case 2:
{
runnerPrices.TotalAmountMatched = mGlobalSession.ConvertToBase(Double.Parse(token), currency);
break;
}
case 3:
{
if (token != string.Empty)
{
runnerPrices.LastPriceMatched = Double.Parse(token);
}
break;
}
case 4:
{
if (token != string.Empty)
{
runnerPrices.Handicap = Double.Parse(token);
}
break;
}
case 5:
{
if (token != string.Empty)
{
runnerPrices.ReductionFactor = Double.Parse(token);
}
break;
}
case 6:
{
if (token != string.Empty)
{
runnerPrices.Vacant = Boolean.Parse(token);
}
break;
}
case 7:
{
if (token != string.Empty)
{
if (token.Equals("NaN") || token.Equals("Infinity"))
{
runnerPrices.FarSPPrice = 0;
}
else
{
runnerPrices.FarSPPrice = Double.Parse(token);
}
}
break;
}
case 8:
{
if (token != string.Empty)
{
if (token.Equals("NaN") || token.Equals("Infinity"))
{
runnerPrices.NearSPPrice = 0;
}
else
{
runnerPrices.NearSPPrice = Double.Parse(token);
}
}
break;
}
case 9:
{
if (token != string.Empty)
{
if (token.Equals("NaN") || token.Equals("Infinity"))
{
runnerPrices.ActualSPPrice = 0;
}
else
{
runnerPrices.ActualSPPrice = Double.Parse(token);
}
}
break;
}
}
}
return runnerPrices;
}i'm steve
have just joined this forum.
am trying to write my own program using the free api using visual basic net.
don't really know much about programming but thought my solution to GCMPC may interest others, although i am still working on it.
was also wondering about GetMarketTradedVolumeCompressed as i was going to use this one too, but it does not look right to me.
the response is in a different order to that of GCMPC when i am looking at the selection id's of the 2 responses.
surely you would expect the ordering to be the same for these 2????
Dim GCMPC_Req As New bf_AUS.GetCompleteMarketPricesCompressedReq
With GCMPC_Req
.header = BetFair_API6.GetToken("A")
.marketId = BetFair_API6.marketID
End With
Dim GCMPC_Res As New bf_AUS.GetCompleteMarketPricesCompressedResp
GCMPC_Res = My.WebServices.Betfair_API6_bf_AUS_BFExchangeService.getCompleteMarketPricesCompressed(GCMPC_Req)
If GCMPC_Res.errorCode = bf_AUS.GetCompleteMarketPricesErrorEnum.OK Then ' if ok then we have info!!
'first step is to get rid of colons that are not field separators
Dim market As String = GCMPC_Res.completeMarketPrices.Replace("\:", "")
Dim splitData() As String = Split(market, ":") ' now split the data with ":" as the delimiter
Dim marketInfo() As String = Split(splitData(0), "~") ' market info and scratchings
' marketInfo(0) = marketID(Integer)
' marketInfo(1) = inPlayDelay(Integer) should be 0
' marketInfo(2) = removedRunner info 3 fields separated by commas. each removal separated by semicolon
For a As Byte = 1 To splitData.Length - 1 ' all remaining splitData iterations are runner related
Dim thisRunner() As String = Split(splitData(a), "|") ' runnerInfo is split into 2 parts
' 1 runner info / 2 price and amount available info of this runner
Dim infoRunner() As String = Split(thisRunner(0), "~")
' infoRunner(0) = selectionID(integer)
' infoRunner(1) = orderIndex(integer)
' infoRunner(2) = amountMatched(double)
' infoRunner(3) = lastPriceMatched(double)
' infoRunner(4) = handicap(double) ' only applicable to asian handicaps
' infoRunner(5) = reductionFactor(double)
' infoRunner(6) = vacant(boolean) ' irrelevant to horse racing
' infoRunner(7) = asianLineID(integer) ' only for asian handicap markets
' infoRunner(8) = farSPPrice(double) ' no use to us at moment
' infoRunner(9) = nearSPPrice(double) ' no use to us at moment
' infoRunner(8) = actualSPPrice(double) ' no use to us at moment
Dim infoPrice() As String = Split(thisRunner(1), "~")
' infoPrice(0) = price(double) ' the odds
' infoPrice(1) = backAmount(double) ' the amount available to back at these odds
' infoPrice(2) = layAmount(double) ' the amount available to lay at these odds
' infoPrice(3) = totalBSPBackAvailable(double) ' irrelevant to us
' infoPrice(4) = totalBSPLayAvailable(double) ' irrelevant to us
' do whatever
Next
ElseIf GCMPC_Res.errorCode = bf_AUS.GetCompleteMarketPricesErrorEnum.EVENT_CLOSED Then
' do whatever if event is closed
ElseIf GCMPC_Res.errorCode = bf_AUS.GetCompleteMarketPricesErrorEnum.EVENT_SUSPENDED Then
' do whatever if event is suspended
End If
This Topic Is Locked To Guest Posts
It's been a while since this topic was active, if you'd like to get it going again, please post as a registered member