A simple Stock Quote, why so hard?

Dear AppleScripters,

I’ve been beating my head against the wall over what seems to be a simple task. Using applescript to retrieve a stock quote from the internet. All the posts I can find are over 3 years old and the simple Apple supplied “Get Stock Quote” doesn’t function on any machine i’ve tested.

All I’m trying to do is have an apple script take a list of stock quotes i have, go retrieve the newest prices off of the internet and bring them back. I have worked a lot with AppleScript but have little XML/SOAP knowledge. Since Apple seems to include one it shouldn’t be that big a deal to get a simple script that works.

So can any body help me in finding some simple AppleScript code to do the Ticker to Current Stock Price? Or does anybody already have that code written?

i just prefer to have AppleScript do it on it’s own then having to get a third party app or worry about using my browser to go and get the information. Simply put, i have written a small XCode/AppleScript app that stays open and delivers all the information i need (kinda like a widget) but with more specialized content. (Motion sensors in my house, current weather, computers being used, etc)

Please let me know if anybody has any input. It would be much appreciated.

Cheers,
TalonGold

Why roll your own? There are several listed on Google (stock ticker price OS X). I own iStock ($12, shareware) and it does my portfolio nicely.

I can add that I diddled with SOAP at length before deciding I wasn’t going to get there. SOAP is a horror show.

I checked out iStock, very nice, and actually serves some of my needs. The specific reason was to built in a “ticker” of sorts into this application I’m making. Just on the side of this app would be current stock prices of a few stocks. I know people will be like ‘why not use a widget’ this is not a computer I’ll be running on, it’s basically a channel that is broadcasted in my home showing me all the information i need to know at a current moment. A custom full screened app.

Thats why specifically I was looking for a stock script, you wouldn’t think that such simply acquired information would be so hard to find or parse into applescript. ESPECIALLY a feature that APPLE themselves sends along with the computer.

Very strange, anybody else have any suggestions, and thanks for the heads up on iStock, pretty nice little piece of software.

Cheers,
TalonGold

The only SOAP call I’ve ever seen that worked for me was this trivia:


try
	tell application "http://boyzoid.com/comp/randomQuote.cfc"
		set aQuote to call soap {method name:"GetQuote", parameters:{HTMLFormat:false}}
	end tell
	set aList to |item| of aQuote
	repeat with anItem in aList
		if |key| of anItem is "AUTHOR" then
			set auth to value of anItem
		end if
		if |key| of anItem is "QUOTE" then
			set quot to value of anItem
		end if
	end repeat
	set ourQuote to quot & return & " -- " & auth
on error anError
	set ourQuote to false
end try
ourQuote

I just googled your request and came up with a method using URL Access Scripting on tidbits:

http://www.tidbits.com/resources/481/UASYahoo.html

It works fine, just need to change the parsing.

-N

Interesting that it works for you - produces trash for me.

Thanks to nedloh99, i was able to change the parsing and get it to work pretty well. It is nasty and a pretty thrown together script, but once you put in the stock ticker it’ll even translate to the company name, and give the current quote and the time the quote was posted.

So if anybody is interested, give it a try! Hopefully, even though it’s a low use script, Apple will take a note and not give us scripts that don’t work.


property fullQuote : ""

on run
	try
		set myQuote to text returned of (display dialog "What Quote?" default answer "")
		--set myQuote to "MS"
		set daSymbol to allCaps(myQuote)
		-- make a temp file
		set myFile to ((path to temporary items) as string) & "Stock Quote Script Temp"
		-- fetch quote page
		tell application "URL Access Scripting"
			download "http://finance.yahoo.com/q" to file myFile replacing yes form data "s=" & daSymbol & "&d=v1"
			quit
		end tell
		-- read HTML into a variable
		open for access file myFile
		set quoteHTML to (read file myFile to (get eof file myFile))
		close access file myFile
		set myCompanySearchText to " (" & daSymbol & ")</b></td><td align="
		set myCompanyCount to count of myCompanySearchText
		set companyAnswer to ((the offset of myCompanySearchText in quoteHTML))
		set CompanyTimeShare to (characters companyAnswer through (companyAnswer - 30)) of quoteHTML as string
		set companyAnswer2 to ((the offset of "<b>" in CompanyTimeShare))
		set otherCount to count of CompanyTimeShare
		set TheCompany to (characters (companyAnswer2 + 3) through (otherCount - 1)) of CompanyTimeShare as string
		
		set mySearchText to "</small><big><b>"
		set myCount to count of mySearchText
		set myAnswer to ((the offset of mySearchText in quoteHTML) + myCount)
		
		set currentQuote to (characters myAnswer through (myAnswer + 5)) of quoteHTML as string
		my parseTheList(currentQuote)
		set TimeShare to (characters ((myAnswer - myCount) - 3) through ((myAnswer - myCount) - 11)) of quoteHTML as string
		if TimeShare is "4:00PM ET" or TimeShare is "4:01PM ET" then set TimeShare to "market close"
		tell application "Finder" to delete file myFile
		if fullQuote is not "" then
			display dialog TheCompany & "'s current price is $" & fullQuote & " at " & TimeShare & "."
		else
			display dialog "Unable to find a price for " & daSymbol & "."
		end if
	on error
		display dialog "Unable to find stock '" & myQuote & "'"
	end try
end run

on allCaps(daText)
	-- very messy capitalization routine
	copy "" to newText
	repeat with i from 1 to the count of character in daText
		set curChar to character i of daText
		set curNum to ASCII number curChar
		if (curNum > 96) and (curNum < 123) then
			set newText to (newText & (ASCII character (curNum - 32))) as string
		else
			set newText to (newText & curChar) as string
		end if
	end repeat
	return newText
end allCaps

on parseTheList(parseMe)
	--A rough nasty way of making sure you only pick out the numbers in case of a 2 digit or 3 digit price
	set parseMe to every character of parseMe
	set parsedList to {}
	repeat with i from 1 to number of items in parseMe
		set this_item to item i of parseMe
		try
			if this_item is "." then
				copy this_item to the end of parsedList
			else
				set this_item to this_item as number
				copy this_item to the end of parsedList
			end if
		end try
	end repeat
	set fullQuote to parsedList as string
end parseTheList

Adam -

What were you getting?

-N

Not to worry, N, TG’s version works fine for me.

BTW, capitalization is easy (without disturbing numbers or punctuation) this way:

on allCaps(daText)
	set UC to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	set LC to "abcdefghijklmnopqrstuvwxyz"
	considering case
		set char to characters of daText
		repeat with aC in char
			if contents of aC is in LC then set contents of aC to item (offset of aC in LC) of UC
		end repeat
	end considering
	return char as string
end allCaps

set newText to allCaps("Now iS the 1246 and, : so on")
--> "NOW IS THE 1246 AND, : SO ON"

To get numbers only and include a decimal point in the right place, same trick as capitalization works:

on NumsOnly(aString)
	set numStr to ""
	set keepers to "1234567890."
	set strChr to characters of aString
	repeat with C in strChr
		if contents of C is in keepers then set numStr to numStr & contents of C
	end repeat
	return numStr
end NumsOnly

set nums to NumsOnly("some Text & $123.45 >") --> "123.45"

… and this way:


on allCaps(daText)
	return do shell script "echo " & daText & " | tr a-z A-Z"
end allCaps

set newText to allCaps("Now iS the 1246 and, : so on")
--> "NOW IS THE 1246 AND, : SO ON"

Here’s a new version with StefanK’s much simpler capitalization script.


property fullQuote : ""
on run
	try
		with timeout of 7 seconds
			set myQuote to text returned of (display dialog "What Quote?" default answer "")
			--set myQuote to "MS"
			set daSymbol to allCaps(myQuote)
			-- make a temp file
			set myFile to ((path to temporary items) as string) & "Stock Quote Script Temp"
			-- fetch quote page
			tell application "URL Access Scripting"
				download "http://finance.yahoo.com/q" to file myFile replacing yes form data "s=" & daSymbol & "&d=v1"
				quit
			end tell
			-- read HTML into a variable
			open for access file myFile
			set quoteHTML to (read file myFile to (get eof file myFile))
			close access file myFile
			--Get the full name of the company
			set myCompanySearchText to " (" & daSymbol & ")</b></td><td align="
			set myCompanyCount to count of myCompanySearchText
			set companyAnswer to ((the offset of myCompanySearchText in quoteHTML))
			set CompanyTimeShare to (characters companyAnswer through (companyAnswer - 30)) of quoteHTML as string
			set companyAnswer2 to ((the offset of "<b>" in CompanyTimeShare))
			set otherCount to count of CompanyTimeShare
			set TheCompany to (characters (companyAnswer2 + 3) through (otherCount - 1)) of CompanyTimeShare as string
			--Get the current quote
			set mySearchText to "</small><big><b>"
			set myCount to count of mySearchText
			set myAnswer to ((the offset of mySearchText in quoteHTML) + myCount)
			set currentQuote to (characters myAnswer through (myAnswer + 5)) of quoteHTML as string
			--parse the quote to check for 2 or 3 digit prices
			my parseTheList(currentQuote)
			set TimeShare to (characters ((myAnswer - myCount) - 3) through ((myAnswer - myCount) - 11)) of quoteHTML as string
			--check to see if the markets are open or closed
			if TimeShare is "4:00PM ET" or TimeShare is "4:01PM ET" then set TimeShare to "market close"
			tell application "Finder" to delete file myFile
			if fullQuote is not "" then
				display dialog TheCompany & "'s current price is $" & fullQuote & " at " & TimeShare & "."
			else
				display dialog "Unable to find a price for " & daSymbol & "."
			end if
		end timeout
	on error
		display dialog "Unable to find stock '" & myQuote & "'"
	end try
	
end run

on allCaps(daText)
	set newText to (do shell script "echo " & daText & " | tr a-z A-Z")
end allCaps

on parseTheList(parseMe)
	--A rough nasty way of making sure you only pick out the numbers in case of a 2 digit or 3 digit price
	set parseMe to every character of parseMe
	set parsedList to {}
	repeat with i from 1 to number of items in parseMe
		set this_item to item i of parseMe
		try
			if this_item is "." then
				copy this_item to the end of parsedList
			else
				set this_item to this_item as number
				copy this_item to the end of parsedList
			end if
		end try
	end repeat
	set fullQuote to parsedList as string
end parseTheList

When I run it (as downloaded with the " changed to ") it returns this in the dialog (which I’ve declared a variable).

"Yahoo says AAPL last traded at meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">AAPL: Summary for APPLE INC - Yahoo! Finance at $e>

#screen,#masthead{text-align:center;margin:0;width:752px;}
#screen.xpand,#masthead.xpand{width:100%;}
#screen.xpand #yfncsubtit{width:100%;}
#masthead{padding-bottom:12px;}
#leftcol,#rightcol{margin:0;}
#leftcol{width:155px;float:left;}
#rightcol{width:585px;}
#content{width:752px;}
#footer {clear:both;}

///
body{text-align:center;}
#screen{text-align:left;min-width:700px;width:62.5em;width:expression(
document.all.footer ? (document.all.footer.offsetWidth>1000) ? ‘980’+‘px’ : document.all.footer.offsetWidth :‘62.5’+‘em’) ;margin:auto;border:1px solid #FFF;}
#screen.xpand{width:100%; text-align:center}
#portfolio{margin:10px auto;}
#hdrads{margin:10px auto 0 auto;}
#masthead,#leftcol,#rightcol{margin:0;}
#masthead{width:100%;}
#leftcol{float:left;width:18%;}
#rightcol{float:right;width:80%;}
#content{width:100%;}
#footer{clear:both;text-align:center;padding:10px
0;width:60em;margin:auto;border:0px solid #FFF;} #leftNavTable,#yfncmh,#yfncmkttme,#yfncduplgnwrn,#yfncpsnlbar,#yfnctitbar,#y
fncsubtit,#yfncbrobtn,#yfncsumtab,
.yfnc_systitlelinea1,.yfnc_systitlelineb1,.yfnc_modtitlew1{
width:100%;}
#yfncmh{width:100%;}
.yfncsumdatagrid{background:#DCDCDC;width:100%;}
.yfnc_modtitlew2{width:49%;}
/**/

.yfncnhl{color:#666;margin-bottom:10px;}
.yfncnhl .yfncnhlbl{color:#000;width:1.6em;text-align:center;}

#leftcol{display:none;}
#rightcol{display:block;}
-1)?1:0);
var yfimoz = ((yfiagt.indexOf(‘gecko’)>-1&&!yfisaf)?1:0);
var yfiopr = ((yfiagt.indexOf(‘opera’)>-1&&!yfisaf)?1:0);
//–>."

Okay, here’s an interesting one,

if you take this out of my script


on parseTheList(parseMe)
	--A rough nasty way of making sure you only pick out the numbers in case of a 2 digit or 3 digit price
	set parseMe to every character of parseMe
	set parsedList to {}
	repeat with i from 1 to number of items in parseMe
		set this_item to item i of parseMe
		try
			if this_item is "." then
				copy this_item to the end of parsedList
			else
				set this_item to this_item as number
				copy this_item to the end of parsedList
			end if
		end try
	end repeat
	set fullQuote to parsedList as string
end parseTheList

and replace it with


on parseTheList(parseMe)
	set fullQuote to ""
	set keepers to "1234567890."
	set strChr to characters of parseMe
	repeat with C in strChr
		if contents of C is in keepers then set fullQuote to fullQuote & contents of C
	end repeat
	return fullQuote
end parseTheList

It would seem that Yahoo will give the Stock quote to the third decimal place, so a search for SCHW (Charles Schwab) you can get a price of $21.325, while my original one will only go to the 2nd place and drop off the remainder. Not sure if thats a good or a bad thing, Yahoo DOES actually give it to you to that detail, but rarely do I think i’d have to know what kind of half cents a stock is trading at.

Is there an easier way to use the simplified parsing script but only have it go to the 2nd decimal place? For all standard purposes I’d only need actually dollars, instead of the “Gas Pumping” style that yahoo puts out.

Cheers,
TalonGold

Adam,

That was just the parsing thing I mentioned. I thought you were getting something COMPLETELY odd.

-N