Thread here: viewtopic.php?f=6&t=22924&hilit=programatically
I only did it as a test and it had a few issues with name matching against the market name, given that team names (and even spelling) differ from BF and site to site i.e Manchester United, Man United, Manchester Utd, Man Utd. Horses, Tennis and Dogs etc have names that are common but football is a lot harder.
I've had a bit of spare time as I've been self isolating over Christmas, so to relieve the boredom I've updated the code. The name matching is improved by splitting out each word over 3 characters in the market name, ignoring commonly used words such as "City", "Town", "Hapoel", "Real" etc and then checking to see if at least 2 words are matched across both Home and Away team names. I would have liked to have used 3 or more words but some games only have 2 words in the Market name i.e "Rangers vs Celtic"
I've included some of the commonly used In-Play stats and I've also been able to grab the values in the Sofascore Momentum graph and calc 3 values (5 Min average, 10 Min average, Match Average)
Match Start time is also passed in each SV help prevent any mismatches.
Script:
This runs in a language called Auto-It. It's a fork of AutoHotKey and is pretty powerful.
To run the script you will need to download the program and Scite Editor from here:
https://www.autoitscript.com/site/autoit/downloads/
There are 2 additional User Defined Functions required called Json.au3 and BinaryCall.au3. I've put them in a shared folder on my Google Drive here:
https://drive.google.com/drive/folders/ ... sp=sharing
Copy both files to your Auto-It Includes folder (typically here C:\Program Files (x86)\AutoIt3\Include)
Once installed, paste the code below into the Scite Editor and save to a local folder as Football.au3 (or whatever name you wish)
Then, in Scite do "Tools - Go" and the script will start
The script will run in a 30s timed loop, pulling down the team names and current scores for all currently LIVE games in Sofascore. It will then save those results to a file called "c:\temp\sofascore.csv". You will need to create that folder if it doesnt exist already.
NOTES:
Be careful adjusting the speed of the script loop ( line 259). Lower than 10s and you risk your IP being blocked by SofaScore for too many accesses per minute.
Its possible to compile the script as an exe in Scite so you can just double click it whenever you have footy automation running. Scite - Tools - Compile. Just go with the defaults. Remember to kill (in the Task bar) when trading is over.
****************
Because of the way this is designed, there may be the odd file lockout where both Guardian and the script are trying to read/write the CSV file at the same time. BetAngel Support have confirmed that in this case Guardian will only read and use the entire file when unlocked. There is no chance of partial reads of the data and a problem with the SV's. In this case, the SV's will just update when the file is unlocked again i.e the script has finished writing. If this happens you will see a corresponding log entry in Guardian
****************
Script Edits.
Lines 17-20
;Turn Stats/Graph data on/off
$StatsOn = "Yes"
$GraphOn = "Yes"
Scores will always be returned but by editing "Yes" to "No" you can turn off either to improve the speed if you aren't using them, and only need the scores or just scores\stats. Momentum may prove slow at 3pm on a Sat as it has to loop through every value for the match - though I dont know the algorithm used by SS I assume its a combo of various stats so could be too useful to turn off.
NOTE: Many lesser league matches only provide the score - no stats or momentum. In those cases only the score is passed
Lines 87-88
;#########Uncomment the next line (remove the ";") to view available stats in the console on each loop
;Json_Dump($data3).
Uncommenting the Json_Dump command will dump all returned JSON code to the Scite console. This shows all available stats and allows you to add/edit your own in the script if you have the ability. Only use briefly as it really slows down the script.
Line 43
;Calls function to filter out unwanted match types (Women, U19 etc)
If _MatchCheck(Json_Get($object, '.events[' & $i & '].tournament.name')) = "Yes" Then
This line calls a function (at bottom of script) to check if the League (or a word in the league title) is not required and will ignore it if in the list. Editing out many of the leagues you don't trade will speed up the script on busy days and prevent getting data you dont need
Note: this may work better long term if it just picked the leagues required. May edit in the future
****************
The attached BAF will pull the created SV values into Guardian when applied to a match, and constantly write them to the log. You will want to turn off the log writes for each value once you are happy they are working, otherwise your log will fill quickly. I've also included an off the top of my head LTD rule just to demo the stats (no idea how that one would play out in a real match)
I've been testing in the MO markets but the code\baf will work on any markets that contain the team names in the title. I've also made all SV's Shared Event one's so can be used across all markets for the Event - CS, BTTS, MO etc. Run on MO and use in any related market you like
Log Example:
28/12/2021 08:21:33: [G_Auto 2] : Store Value (Shared) for event: HomeScore = 0
28/12/2021 08:21:33: [G_Auto 2] : Store Value (Shared) for event: AwayScore = 0
28/12/2021 08:21:33: [G_Auto 2] : Store Value (Shared) for event: SOTHome = 4
28/12/2021 08:21:33: [G_Auto 2] : Store Value (Shared) for event: SOTAway = 2
28/12/2021 08:21:33: [G_Auto 2] : Store Value (Shared) for event: SOFFTHome = 7
28/12/2021 08:21:33: [G_Auto 2] : Store Value (Shared) for event: SOFFTAway = 0
28/12/2021 08:21:33: [G_Auto 2] : Store Value (Shared) for event: CornersHome = 6
28/12/2021 08:21:33: [G_Auto 2] : Store Value (Shared) for event: CornersAway = 1
28/12/2021 08:21:33: [G_Auto 2] : Store Value (Shared) for event: BigChanceHome = 3
28/12/2021 08:21:33: [G_Auto 2] : Store Value (Shared) for event: BigChanceAway = 0
28/12/2021 08:21:33: [G_Auto 2] : Store Value (Shared) for event: PassesHome = 252
28/12/2021 08:21:33: [G_Auto 2] : Store Value (Shared) for event: PassesAway = 198
28/12/2021 08:21:33: [G_Auto 2] : Store Value (Shared) for event: PossessionHome = 57
28/12/2021 08:21:33: [G_Auto 2] : Store Value (Shared) for event: PossessionAway = 43
28/12/2021 08:21:33: [G_Auto 2] : Store Value (Shared) for event: 5MinAvgPressure = 11
28/12/2021 08:21:33: [G_Auto 2] : Store Value (Shared) for event: 10MinAvgPressure = 32
28/12/2021 08:21:33: [G_Auto 2] : Store Value (Shared) for event: MatchAvgPressure = 25
I've also added in a heartbeat "Update" SV that increments every script loop. By checking this SV has changed in the last say, 120s, your bot will know that stats are current and the script/API hasn't crashed and you are using old data
Hopefully I've covered everything off, but shout if you have any questions or suggestions. I was in IT but not a dev\coder by trade so this is all self taught stuff for me. There may be better\faster ways to do the above so feel free to chip in
Happy New Year !
Stu
Code: Select all
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Outfile=SS_Football.exe
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <Inet.au3>
#include <json.au3>
#include <Array.au3>
#include <String.au3>
#include <File.au3>
#include <Date.au3>
Local $HomeString, $AwayTeam1
$Update = 0
;Turn Stats/Graph data on/off
$StatsOn = "Yes"
$GraphOn = "Yes"
While 1
$Update = $Update + 1
Local $aMyTable, $aHoldingArray[0][100]
$URL = "https://api.sofascore.com/api/v1/sport/football/events/live"
$data = _INetGetSource($URL)
;Json_Dump($data)
$object = json_decode($data)
Local $Count = Json_Get($object, '.events')
;_ArrayDisplay($Count)
For $i = 0 To UBound($Count) - 1
;Calls function to filter out unwanted match types (Women, U19 etc)
If _MatchCheck(Json_Get($object, '.events[' & $i & '].tournament.name')) = "Yes" Then
;Set impossible starting values for Score
$HomeScore = -1
$AwayScore = -1
$HomeTeam = Json_Get($object, '.events' & '[' & $i & '].homeTeam.name')
$AwayTeam1 = Json_Get($object, '.events' & '[' & $i & '].awayTeam.name')
$HomeScore = Json_Get($object, '.events' & '[' & $i & '].homeScore.current')
$AwayScore = Json_Get($object, '.events' & '[' & $i & '].awayScore.current')
$UnixTime = Json_Get($object, '.events' & '[' & $i & '].startTimestamp')
$aCall = DllCall("msvcrt.dll", "str:cdecl", "ctime", "int*", $UnixTime)
$tmp = StringSplit($aCall[0], " ")
$StartTime = StringTrimRight($tmp[4],3)
;MsgBox("", "", $HomeTeam & ":" & $AwayTeam1 & " " & $HomeScore & ":" & $AwayScore)
; Get API Stat data
If $StatsOn = "Yes" Then
;Set impossible starting values for Stats
$PossessionHome = -1
$PossessionAway = -1
$SOTHome = -1
$SOTAway = -1
$SOFFTHome = -1
$SOFFTAway = -1
$CornersHome = -1
$CornersAway = -1
$BigChanceHome = -1
$BigChanceAway = -1
$PassesHome = -1
$PassesAway = -1
$URL = "https://api.sofascore.com/api/v1/event/" & Json_Get($object, '.events' & '[' & $i & '].id') & "/statistics"
;MsgBox("", "", $URL)
$data3 = _INetGetSource($URL)
If $data3 <> "" Then
;#########Uncomment the next line (remove the ";") to view available stats in the console on each loop
;Json_Dump($data3)
;MsgBox("", "", $HomeTeam & ":" & $AwayTeam1 & " " & $HomeScore & ":" & $AwayScore)
$object3 = json_decode($data3)
Local $GroupCount = Json_Get($object3, '.statistics[0].groups')
;_ArrayDisplay($GroupCount)
For $c = 0 To UBound($GroupCount)
If Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[0].name') = "Ball possession" Then
$PossessionHome = StringReplace(Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[0].home '), "%", "")
$PossessionAway = StringReplace(Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[0].away'), "%", "")
;MsgBox("", "", $PossessionHome & ":" & $PossessionAway)
EndIf
If Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[1].name') = "Shots on target" Then
$SOTHome = Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[1].home')
$SOTAway = Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[1].away')
;MsgBox("On", "On", $SOTHome & ":" & $SOTAway)
EndIf
If Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[2].name') = "Shots off target" Then
$SOFFTHome = Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[2].home')
$SOFFTAway = Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[2].away')
;MsgBox("Off", "Off", $SOFFTHome & ":" & $SOFFTAway)
EndIf
If Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[0].name') = "Corner kicks" Then
$CornersHome = Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[0].home')
$CornersAway = Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[0].away')
;MsgBox("Corners", "Corners", $CornersHome & ":" & $CornersAway)
EndIf
If Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[0].name') = "Big chances" Then
$BigChanceHome = Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[0].home')
$BigChanceAway = Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[0].away')
;MsgBox("Chance", "Chance", $BigChanceHome & ":" & $BigChanceAway)
EndIf
If Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[0].name') = "Passes" Then
$PassesHome = Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[0].home')
$PassesAway = Json_Get($object3, '.statistics[0].groups[' & $c & '].statisticsItems[0].away')
;MsgBox("Passes", "Passes", $PassesHome & ":" & $PassesAway)
EndIf
Next
EndIf
EndIf
; Get API Graph data
If $GraphOn = "Yes" Then
;Set impossible starting values for Graph
$5MinAvgPressure = -100
$10MinAvgPressure = -100
$MatchAvgPressure = -100
$URL = "https://api.sofascore.com/api/v1/event/" & Json_Get($object, '.events' & '[' & $i & '].id') & "/graph "
;MsgBox("", "", $URL)
$data2 = _INetGetSource($URL)
If $data2 <> "" Then
;Json_Dump($data2)
$object2 = json_decode($data2)
Local $Count = Json_Get($object2, '.graphPoints')
;_ArrayDisplay($Count)
;5 Min Average
$GraphTotal = 0
$GraphCount = 0
For $y = UBound($Count) - 1 To 0 Step -1
;$Convert = StringReplace(Json_Get($object2, '.graphPoints' & '[' & $y & '].value'), "-", "")
$Convert = Json_Get($object2, '.graphPoints' & '[' & $y & '].value')
$GraphTotal = $GraphTotal + $Convert
$GraphCount = $GraphCount + 1
If $GraphCount = 5 Then ExitLoop
Next
$GraphAverage = 0
$GraphAverage = Round($GraphTotal / $GraphCount)
If StringInStr($GraphAverage, "IND") Then
$5MinAvgPressure = 99
Else
$5MinAvgPressure = $GraphAverage
EndIf
;10 Min Average
$GraphTotal = 0
$GraphCount = 0
For $y = UBound($Count) - 1 To 0 Step -1
;$Convert = StringReplace(Json_Get($object2, '.graphPoints' & '[' & $y & '].value'), "-", "")
$Convert = Json_Get($object2, '.graphPoints' & '[' & $y & '].value')
$GraphTotal = $GraphTotal + $Convert
$GraphCount = $GraphCount + 1
If $GraphCount = 10 Then ExitLoop
Next
$GraphAverage = 0
$GraphAverage = Round($GraphTotal / $GraphCount)
If StringInStr($GraphAverage, "IND") Then
$10MinAvgPressure = 99
Else
$10MinAvgPressure = $GraphAverage
EndIf
;Match Average
$GraphTotal = 0
$GraphCount = 0
For $y = UBound($Count) - 1 To 0 Step -1
;$Convert = StringReplace(Json_Get($object2, '.graphPoints' & '[' & $y & '].value'), "-", "")
$Convert = Json_Get($object2, '.graphPoints' & '[' & $y & '].value')
$GraphTotal = $GraphTotal + $Convert
$GraphCount = $GraphCount + 1
Next
$GraphAverage = 0
$GraphAverage = Round($GraphTotal / $GraphCount)
If StringInStr($GraphAverage, "IND") Then
$MatchAvgPressure = 99
Else
$MatchAvgPressure = $GraphAverage
EndIf
EndIf
EndIf
Local $TeamFinal = _ReturnTeams()
For $a = 0 To UBound($TeamFinal) - 1
$BuildString = "*" & _StringReplaceAccent($TeamFinal[$a]) & "*|" & $StartTime & "|*|*|E|Name" & $a & "|1|E|HomeScore1|" & $HomeScore & "|E|AwayScore1|" & $AwayScore
If $StatsOn = "Yes" Then
$BuildString = $BuildString & "|E|SOTHome1|" & $SOTHome & "|E|SOTAway1|" & $SOTAway & "|E|SOFFTHome1|" & $SOFFTHome & "|E|SOFFTAway1|" & $SOFFTAway & "|E|CornersHome1|" & $CornersHome & "|E|CornersAway1|" & $CornersAway & "|E|BigChanceHome1|" & $BigChanceHome & "|E|BigChanceAway1|" & $BigChanceAway & "|E|PassesHome1|" & $PassesHome & "|E|PassesAway1|" & $PassesAway & "|E|PossessionHome1|" & $PossessionHome & "|E|PossessionAway1|" & $PossessionAway
EndIf
If $GraphOn = "Yes" Then
$BuildString = $BuildString & "|E|5MinAvgPressure1|" & $5MinAvgPressure & "|E|10MinAvgPressure1|" & $10MinAvgPressure & "|E|MatchAvgPressure1|" & $MatchAvgPressure
EndIf
_ArrayAdd($aHoldingArray, $BuildString)
Next
EndIf
Next
;Add Heartbeat to array/update
_ArrayAdd($aHoldingArray, "*|*|*|*|E|Update|" & $Update)
;_ArrayDisplay($aHoldingArray)
_FileWriteFromArray("c:\temp\sofascore.csv", $aHoldingArray, Default, Default, ",")
_FileWriteToLine("c:\temp\sofascore.csv", 1, "1", False)
ConsoleWrite(_NowTime() & @CRLF)
;Wait time between score refresh in milliseconds
;#######DO NOT SET SHORTER THAN 10S AS YOUR IP MAY BE BLOCKED#####
Sleep(30000) ;30 seconds
WEnd
Func _NameCheck($Word)
If StringInStr($Word, "http") Then
Return "No"
ElseIf StringInStr($Word, "vs") Then
Return "No"
ElseIf StringInStr($Word, "Hapoel") Then
Return "No"
ElseIf StringInStr($Word, "Club") Then
Return "No"
ElseIf StringInStr($Word, "City") Then
Return "No"
ElseIf StringInStr($Word, "Town") Then
Return "No"
ElseIf StringInStr($Word, "U23") Then
Return "No"
ElseIf StringInStr($Word, "Utd") Then
Return "No"
ElseIf StringInStr($Word, "VPV") Then
Return "No"
ElseIf StringInStr($Word, "VPS") Then
Return "No"
ElseIf StringInStr($Word, "Citizen") Then
Return "No"
ElseIf StringInStr($Word, "Club") Then
Return "No"
ElseIf StringInStr($Word, "TSV") Then
Return "No"
ElseIf StringInStr($Word, "TSG") Then
Return "No"
ElseIf StringInStr($Word, "Tblisi") Then
Return "No"
ElseIf StringInStr($Word, "Women") Then
Return "No"
ElseIf StringInStr($Word, "U16") Then
Return "No"
ElseIf StringInStr($Word, "U17") Then
Return "No"
ElseIf StringInStr($Word, "U19") Then
Return "No"
ElseIf StringInStr($Word, "U21") Then
Return "No"
ElseIf StringInStr($Word, "U23") Then
Return "No"
ElseIf StringInStr($Word, "U20") Then
Return "No"
ElseIf StringInStr($Word, "(W)") Then
Return "No"
ElseIf StringInStr($Word, "United") Then
Return "No"
ElseIf StringInStr($Word, "Maccabi") Then
Return "No"
ElseIf StringInStr($Word, "Viit") Then
Return "No"
ElseIf StringInStr($Word, "USD") Then
Return "No"
ElseIf StringInStr($Word, "Beitar") Then
Return "No"
ElseIf StringInStr($Word, "Bucu") Then
Return "No"
ElseIf StringInStr($Word, "Buch") Then
Return "No"
ElseIf StringInStr($Word, "FCV") Then
Return "No"
ElseIf StringInStr($Word, "Spart") Then
Return "No"
ElseIf StringInStr($Word, "Unirea") Then
Return "No"
ElseIf StringInStr($Word, "Dinamo") Then
Return "No"
ElseIf StringInStr($Word, "Dynamo") Then
Return "No"
ElseIf StringInStr($Word, "Tblis") Then
Return "No"
ElseIf StringInStr($Word, "Youth") Then
Return "No"
ElseIf StringInStr($Word, "Atletico") Then
Return "No"
ElseIf StringInStr($Word, "Athletic") Then
Return "No"
ElseIf StringInStr($Word, "Real") Then
Return "No"
Else
Return "Yes"
EndIf
EndFunc ;==>_NameCheck
Func _StringReplaceAccent($sString)
Local $exp, $rep
Local $Pattern[29][2] = [ _
["[ÀÁÂÃÅÆ]", "A"], ["[àáâãåą]", "a"], ["Ä", "Ae"], ["[æä]", "ae"], _
["Þ", "B"], ["þ", "b"], _
["ÇĆ", "C"], ["[çćč]", "c"], _
["[ÈÉÊË]", "E"], ["[èéêë]", "e"], _
["[ÌÍÎÏ]", "I"], ["[ìíîï]", "i"], _
["Ñ", "N"], ["ñ", "n"], _
["[ÒÓÔÕÖØ]", "O"], ["[ðòóôõöø]", "o"], _
["ř", "r"], _
["[ŠŚ]", "S"], ["[š]", "s"], _
["ß", "Ss"], _
["Ț", "T"], _
["[ÙÚÛ]", "U"], ["[ùúû]", "u"], ["Ü", "Ue"], ["ü", "ue"], _
["Ý", "Y"], ["[ýýÿ]", "y"], _
["Ž", "Z"], ["ž", "z"]]
For $i = 0 To (UBound($Pattern) - 1)
$exp = $Pattern[$i][0]
If $exp = "" Then ContinueLoop
$rep = $Pattern[$i][1]
$sString = StringRegExpReplace($sString, $exp, $rep)
If @error == 0 And @extended > 0 Then
;ConsoleWrite($sString & @LF & "--> " & $exp & @LF)
EndIf
Next
Return $sString
EndFunc ;==>_StringReplaceAccent
Func _MatchCheck($Word)
If StringInStr($Word, "Esports") Then
Return "No"
ElseIf StringInStr($Word, "Friend") Then
Return "No"
;ElseIf StringInStr($Word, "Women") Then
Return "No"
;ElseIf StringInStr($Word, "(W)") Then
Return "No"
ElseIf StringInStr($Word, "Reserves") Then
Return "No"
ElseIf StringInStr($Word, "U16") Then
Return "No"
ElseIf StringInStr($Word, "U17") Then
Return "No"
ElseIf StringInStr($Word, "Youth") Then
Return "No"
;ElseIf StringInStr($Word, "U19") Then
; Return "No"
;ElseIf StringInStr($Word, "U21") Then
; Return "No"
;ElseIf StringInStr($Word, "U20") Then
; Return "No"
;ElseIf StringInStr($Word, "Cup") Then
; Return "No"
;ElseIf StringInStr($Word, "Copa") Then
; Return "No"
Else
Return "Yes"
EndIf
EndFunc ;==>_MatchCheck
Func _ReturnTeams()
Local $TeamArray = StringSplit($HomeTeam, " ", 2)
Local $AwayTeam = StringSplit($AwayTeam1, " ", 2)
Local $TeamFinalFunc[0]
_ArrayConcatenate($TeamArray, $AwayTeam)
For $f = 0 To UBound($TeamArray) - 1
$TeamArray[$f] = StringStripWS($TeamArray[$f], 8)
Next
;_ArrayDisplay($TeamArray)
For $x = 0 To UBound($TeamArray) - 1
If StringInStr($TeamArray[$x], "-") And StringLen($TeamArray[$x]) > 4 Then
$HyphenSplit = StringSplit($TeamArray[$x], "-", 2)
;_ArrayDisplay($HyphenSplit)
For $d = 0 To UBound($HyphenSplit) - 1
If StringLen($HyphenSplit[$d]) > 3 And _NameCheck($TeamArray[$x]) = "Yes" Then
_ArrayAdd($TeamFinalFunc, StringLeft($HyphenSplit[$d], 6))
EndIf
Next
ElseIf StringLen($TeamArray[$x]) > 3 And _NameCheck($TeamArray[$x]) = "Yes" Then
_ArrayAdd($TeamFinalFunc, StringLeft($TeamArray[$x], 6))
EndIf
Next
;_ArrayDisplay($TeamFinalFunc)
Return ($TeamFinalFunc)
EndFunc ;==>_ReturnTeams