Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Stock Ticker
#1
This is purely visual, and uses random numbers as proof of concept.  Though, the update function is fairly easy to spot, so if you want to actually check live stock prices, that shouldn't be hard for you to do.

When it runs, it checks the available resolutions your monitor can support, so it makes itself as wide as is possible, at the top of the screen, and after a little initialization, starts scrolling quotes.

import pygame
import random
import time

WHITE = (255, 255, 255)
BLACK = (  0,   0,   0)
RED =   (255,   0,   0)
GREEN = (  0, 255,   0)

""" 
	TickerItem cares about WHAT it looks like, not WHERE it is.
	The TickerGroup handles positioning.
"""
class TickerItem(object):
	font = None
	
	@classmethod
	def get_font(cls):
		if not cls.font:
			pygame.font.init()
			cls.font = pygame.font.SysFont("lucidafax", 16, True)
		return cls.font
	
	def __init__(self, ticker):
		self.symbol = ticker[0]
		self.value = self.initial_value = round(ticker[1], 2)
		self.last_update = 0
		self.update()
		self.inital_value = self.value
		
	def render_text(self):
		text = "{0} [{1:.2f}]".format(self.symbol, self.value)
		font = self.get_font()
		color = WHITE
		if self.value > self.initial_value:
			color = GREEN
		elif self.value < self.initial_value:
			color = RED
		self.surface = font.render(text, True, color, BLACK)
		self.text_size = font.size(text)
		
	def update(self):
		# only update the value once every 10 seconds
		if time.time() - self.last_update > 10:
			self.value += (random.random() * random.choice([1, -1]))
			self.value = round(self.value, 2)
			self.render_text()
			self.last_update = time.time()

""" 
	Maintains a list of TickerItems, and their positions in space.
	TickerGroup handles moving the TickerItems around,
		but doesn't care about what they look like or what they say.
"""
class TickerGroup(object):
	def __init__(self, screen, tickers):
		self.distance = 10
		self.screen = screen
		self.tickers = []
		# uncomment if you want the ticker to be blank when it starts,
		# and for all stocks to creep in, instead of being started full of tickers
		xpos = 5 # self.screen.get_width()
		for ticker in tickers:
			tcker = TickerItem(ticker)
			pos = [xpos, 0]
			self.tickers.append({
				"ticker": tcker,
				"position": pos
			})
			xpos += tcker.text_size[0] + self.distance
		self.last = xpos
	
	def update(self):
		for ticker in self.tickers:
			ticker['ticker'].update()
			ticker['position'][0] -= 1
			text_size = ticker['ticker'].text_size[0]
			if ticker['position'][0] + text_size < 0:
				ticker['position'][0] = self.last
			self.last = ticker['position'][0] + text_size + self.distance
			self.screen.blit(ticker['ticker'].surface, ticker['position'])

if __name__ == '__main__':
	# set the window to be at the top of the screen
	import os
	os.environ['SDL_VIDEO_WINDOW_POS'] = "0,0"

	pygame.init()
	# find the current resolution, and use that as our width so we stretch across the screen
	sizes = pygame.display.list_modes()
	screen_size = (sizes[0][0], 20)
	screen = pygame.display.set_mode(screen_size, pygame.NOFRAME)
	
	clock = pygame.time.Clock()
	
	ticker = TickerGroup(screen, [
		["SPY", 200],
		["AAPL", 115],
		["AXP", 63],
		["BA", 130],
		["BAC", 15],
		["CAT", 82],
		["CSCO", 30],
		["CVX", 98],
		["DD", 66],
		["GE", 30],
		["IBM", 153],
		["MCD", 116],
		["MMM", 175],
		["MSFT", 57],
		["PG", 87],
		["UNH", 139],
		["UTX", 102],
		["V", 82],
		["VZ", 52],
		["XOM", 83]
	])
	
	running = True
	while running:
		for event in pygame.event.get():
			if event.type == pygame.QUIT:
				running = False
			if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
				running = False
		screen.fill(BLACK)
		
		ticker.update()
		
		pygame.display.flip()
		clock.tick(60)
	pygame.quit()

Attached Files

Thumbnail(s)
   
#2
Hello,

Take a look at the following post, and download the JSON file (get Record.py from Record so you can read it all)
It has lots of sources for stock market data. I also have a program which uses that file and downloads all of the data
automatically (if you want it - let me know). This would be a great addition to your game.

Post: http://pyforum.io/topic/46/still-playing...cord-class


Larz60+
[url=https://github.com/Larz60p/Python-Record-Structure][/url]
#3
It isn't a game. pygame just happens to be the easiest way to draw to the screen I've seen so far with python. Perhaps a pysdl would be better, though.
#4
(Sep-26-2016, 09:32 PM)nilamo Wrote: It isn't a game.  pygame just happens to be the easiest way to draw to the screen I've seen so far with python.  Perhaps a pysdl would be better, though.

object oriented programming started out as a game.  game stuff can be very useful.
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.
#5
Now with a new addition!  The amount changed since startup (ideally since the start of the trading day) is shown, along with an arrow indicating positive or negative (for the colorblind :)

import pygame
import random
import time

WHITE = (255, 255, 255)
BLACK = (  0,   0,   0)
RED =   (255,   0,   0)
GREEN = (  0, 255,   0)

""" 
	TickerItem cares about WHAT it looks like, not WHERE it is.
	The TickerGroup handles positioning.
"""
class TickerItem(object):
	font = None
	
	@classmethod
	def get_font(cls):
		if not cls.font:
			pygame.font.init()#lucidafax
			cls.font = pygame.font.SysFont("monospace", 16, True)
		return cls.font
	
	def __init__(self, ticker):
		self.symbol = ticker[0]
		self.value = self.initial_value = round(ticker[1], 2)
		self.last_update = 0
		self.update()
		self.inital_value = self.value
		
	def render_text(self):
		color = WHITE
		if self.value > self.initial_value:
			color = GREEN
		elif self.value < self.initial_value:
			color = RED
		difference = self.value - self.initial_value
		arrow = '\u25B2' if difference > 0 else '\u25BC'
		text = "{0}[{1:.2f}{2}{3:.2f}]".format(self.symbol, self.value, arrow, abs(difference))
		font = self.get_font()
		self.surface = font.render(text, True, color, BLACK)
		self.text_size = font.size(text)
		
	def update(self):
		# only update the value once every 10 seconds
		if time.time() - self.last_update > 10:
			self.value += (random.random() * random.choice([1, -1]))
			self.value = round(self.value, 2)
			self.render_text()
			self.last_update = time.time()

""" 
	Maintains a list of TickerItems, and their positions in space.
	TickerGroup handles moving the TickerItems around,
		but doesn't care about what they look like or what they say.
"""
class TickerGroup(object):
	def __init__(self, screen, tickers):
		self.distance = 10
		self.screen = screen
		self.tickers = []
		# uncomment if you want the ticker to be blank when it starts,
		# and for all stocks to creep in, instead of being started full of tickers
		xpos = 5 # self.screen.get_width()
		for ticker in tickers:
			tcker = TickerItem(ticker)
			pos = [xpos, 0]
			self.tickers.append({
				"ticker": tcker,
				"position": pos
			})
			xpos += tcker.text_size[0] + self.distance
		self.last = xpos
	
	def update(self):
		for ticker in self.tickers:
			ticker['ticker'].update()
			ticker['position'][0] -= 1
			text_size = ticker['ticker'].text_size[0]
			if ticker['position'][0] + text_size < 0:
				ticker['position'][0] = self.last
			self.last = ticker['position'][0] + text_size + self.distance
			self.screen.blit(ticker['ticker'].surface, ticker['position'])

if __name__ == '__main__':
	# set the window to be at the top of the screen
	import os
	os.environ['SDL_VIDEO_WINDOW_POS'] = "0,0"

	pygame.init()
	# find the current resolution, and use that as our width so we stretch across the screen
	sizes = pygame.display.list_modes()
	screen_size = (sizes[0][0], 20)
	screen = pygame.display.set_mode(screen_size, pygame.NOFRAME)
	
	clock = pygame.time.Clock()
	
	ticker = TickerGroup(screen, [
		["SPY", 200],
		["AAPL", 115],
		["AXP", 63],
		["BA", 130],
		["BAC", 15],
		["CAT", 82],
		["CSCO", 30],
		["CVX", 98],
		["DD", 66],
		["GE", 30],
		["IBM", 153],
		["MCD", 116],
		["MMM", 175],
		["MSFT", 57],
		["PG", 87],
		["UNH", 139],
		["UTX", 102],
		["V", 82],
		["VZ", 52],
		["XOM", 83]
	])
	
	running = True
	while running:
		for event in pygame.event.get():
			if event.type == pygame.QUIT:
				running = False
			if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
				running = False
		screen.fill(BLACK)
		
		ticker.update()
		
		pygame.display.flip()
		clock.tick(60)
	pygame.quit()

Attached Files

Thumbnail(s)
   
#6
Hi,

I called mine part of a a game for a specific reason. I didn't want someone to use it and make a bad $$ decision!
It could be the basis for a great trading program, but not there yet. The code that goes with this is voluminous,
has hooks for daily downloads on many US, European, And Asian market data, then converts it all to an sqlite3
database, all that is working now.
 
It includes real time quotes, mutual funds, option data including daily strikes, nasdaq, nyse and amex stocks
including all ticker information .

I'm going to post it on github shortly because I've become temporarily burnt out on it, just when I'm ready to create
a supporting GUI. Hopefully someone else will pick up where I left off.

Larz60+
#7
How did you get real time data? The free sources I've seen are delayed 15ish minutes...
#8
Hi Nilamo,

Yahoo real time quotes are still available.
Use the following link: http://finance.yahoo.com/d/quotes.csv?s=" +T + "&f=sl1d1t1c1ohgv&e=.csv

I was using google real time which was also still available, but haven't been able to lately, so I guess they finally shut it down completely.

Here's an article that may have additional information: Yahoo realtime quotes


Larz60+
#9
Hi Nilamo,

Just for chuckles, I tried Google finance, and low and behold the API is still alive! No guarantee on how long,
but here's the code I used (source in comment at top) modified for python 3.4


# Credits: Obtained from the blog at: http://digitalpbk.com/stock/google-finance-get-stock-quote-realtime
import urllib.request as ur
import time


class GoogleRealTime:
    def __init__(self):
        self.prefix = "http://finance.google.com/finance/info?client=ig&q="

    def get(self, symbol, exchange):
        url = self.prefix+"%s:%s"%(exchange, symbol)
        u = ur.urlopen(url)
        content = u.read()
        # obj = json.loads(content[3:])
        return content


if __name__ == "__main__":
    c = GoogleRealTime()

    while 1:
        quote = c.get("MSFT", "NASDAQ")
        print (quote)
        time.sleep(30)
I feel like I am abusing this thread. It's supposed to be snippets, but there is one more very useful post I'd like to include.

Here's a dictionary of the Yahoo quote tags:
class YahooTags:
    def __init__(self):
        self.yahoo_tags = {
            'Ask': 'a',
            'Average Daily Volume': 'a2',
            'Ask Size': 'a5',
            'Bid': 'b',
            'Ask (Real-time)':'b2',
            'Bid (Real-time)':'b3',
            'Book Value':'b4',
            'Bid Size':'b6',
            'Change & Percent Change':'c',
            'Change':'c1',
            'Commission':'c3',
            'Change (Real-time)':'c6',
            'After Hours Change (Real-time)':'c8',
            'Dividend/Share':'d',
            'Last Trade Date':'d1',
            'Trade Date': 'd2',
            'Earnings/Share': 'e',
            'Error Indication (returned for symbol changed / invalid)': 'e1',
            'EPS Estimate Current Year': 'e7',
            'EPS Estimate Next Year': 'e8',
            'EPS Estimate Next Quarter': 'e9',
            'Float Shares': 'f6',
            'Day’s Low': 'h',
            'Day’s High': 'g',
            '52-week Low': 'j',
            '52-week High': 'k',
            'Holdings Gain Percent': 'g1',
            'Annualized Gain': 'g3',
            'Holdings Gain': 'g4',
            'Holdings Gain Percent (Real-time)': 'g5',
            'Holdings Gain (Real-time)': 'g6',
            'More Info': 'i',
            'Order Book (Real-time)': 'i5',
            'Market Capitalization': 'j1',
            'Market Cap (Real-time)': 'j3',
            'EBITDA': 'j4',
            'Change From 52-week Low': 'j5',
            'Percent Change From 52-week Low': 'j6',
            'Last Trade (Real-time) With Time': 'k1',
            'Change Percent (Real-time)': 'k2',
            'Last Trade Size': 'k3',
            'Change From 52-week High': 'k4',
            'Percebt Change From 52-week High': 'k5',
            'Last Trade (With Time)': 'l',
            'Last Trade (Price Only)': 'l1',
            'High Limit': 'l2',
            'Low Limit': 'l3',
            'Day’s Range': 'm',
            'Day’s Range (Real-time)': 'm2',
            '50-day Moving Average': 'm3',
            '200-day Moving Average': 'm4',
            'Change From 200-day Moving Average': 'm5',
            'Percent Change From 200-day Moving Average': 'm6',
            'Change From 50-day Moving Average': 'm7',
            'Percent Change From 50-day Moving Average': 'm8',
            'Name': 'n4', 'Notes': 'n',
            'Open': 'p', 'Previous Close': 'o',
            'Price Paid': 'p1',
            'Change in Percent': 'p2',
            'Price/Sales': 'p5',
            'Price/Book': 'p6',
            'Ex-Dividend Date': 'q',
            'P/E Ratio': 'r',
            'Dividend Pay Date': 'r1',
            'P/E Ratio (Real-time)': 'r2',
            'PEG Ratio': 'r5',
            'Price/EPS Estimate Current Year': 'r6',
            'Price/EPS Estimate Next Year': 'r7',
            'Symbol': 's',
            'Shares Owned': 's1',
            'Short Ratio': 's7',
            'Last Trade Time': 't1',
            'Trade Links': 't6',
            'Ticker Trend': 't7',
            '1 yr Target Price': 't8',
            'Volume': 'v',
            'Holdings Value': 'v1',
            'Holdings Value (Real-time)': 'v7',
            '52-week Range': 'w',
            'Day’s Value Change': 'w1',
            'Day’s Value Change (Real-time)': 'w4',
            'Stock Exchange': 'x',
            'Dividend Yield': 'y',
        }
        self.sendtags()

    def sendtags(self):
        return self.yahoo_tags
Larz60+
#10
(Sep-30-2016, 02:55 PM)Larz60 Wrote: Use the following link: http://finance.yahoo.com/d/quotes.csv?s=" +T + "&f=sl1d1t1c1ohgv&e=.csv
this URL has as its link URL:

http://finance.yahoo.com/d/quotes.csv?s=

this redirects to:

http://download.finance.yahoo.com/d/quotes.csv?s=

which gives me pretty much no real content.  is there more to do?
Tradition is peer pressure from dead people

What do you call someone who speaks three languages? Trilingual. Two languages? Bilingual. One language? American.


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020