LED Stock Indicator

Hello all,

I wanted to share a project of mine. I wanted one of my router's LEDs (a generally unused one) to show movement in a stock in real-time. So, I wrote this script (below) that you could call as an /etc/init.d service, if you'd like (instructions below). It's sudo-code logic is as follows:

loop[
check day & time to see if stocks are trading (premarket + regular hours work fine, afterhours do not)
if time is not ok, wait 600 secs
if time is ok, pull stock data, set LED pattern, then wait 600 secs.
]

LED pattern is as follows:

  • Mostly on blinking corresponds to stock being up, every 1s of LED on between blinks = 1% movement in stock.
    Ex1. Stock up 3.28% would generate a 3.28s on, 50ms off, 3.28s on, 50ms off, repeating pattern.
  • Mostly off blinking corresponds to stock being down, every 1s of LED off between blinks = 1% movement in stock.
    Ex2. Stock down 7.1% would generate a 7.1s off, 50ms on, 7.1s off, 50ms on, repeating pattern.

NOTE: The obervant of you will notice that the pattern would be the same if the stock were up 0.05% or down 0.05%, namely: 0.05s (50ms) on, 0.05s (50ms) off, repeating. I am ok w/ this ambiguity since up/down 0.05% is a fairly trivial move.

See demo video here. For reference my stock was up 1% at the time of recording.

Some configuration/prerequisites needed on your side:

  1. Make sure you have echo, grep, cut, /bin/date, wget (no SSL needed here) and awk available using the following commands:
  • which echo
  • which grep
  • which cut
  • which date
  • which wget
  • which awk
    If you do not have one of these binaries installed, install it w/ opkg.
  1. Change the LED directory (LEDDIR) in the below script to the LED that you want to use.
    (TIP: use the following for a list of system LEDs)

ls -1 /sys/class/leds/

  1. Make sure your chosen LED is unused during normal day-to-day operations and has a non-zero brightness and a timer trigger. Ex: for me, I'd execute the following:

echo 255 > /sys/class/leds/ht-tm02:blue:wlan/brightness
echo timer > /sys/class/leds/ht-tm02:blue:wlan/trigger

  1. Make sure your system time is correct by running /bin/date. If it's not correct, sync with an NTP server. Also, I live in CDT, so premarket opens at 04:00, market closes at 15:00 for me. If your timezone is different, you'll want to change the if statement conditions on line 24 in the below script:

if [ $hour -ge 4 ] && [ $hour -le 15 ]; then

#! /bin/sh
#################################
#	STOCKLED BLINK ON MOVE
#		   BY
#	Joshua Patterson, PhD
#
#	v1.0
#################################

SSymbol=$1
LEDDIR="/sys/class/leds/ht-tm02:blue:wlan"
workDays="Mon Tue Wed Thu Fri"
isOk=0
isOkTime=0
isOkDay=0

echo "STOCKLED service starting..."
while [ true ]; do
	dString=$(/bin/date)
	day=$(echo $dString | cut -d' ' -f1)
	hour=$(echo $dString | cut -d' ' -f4 | cut -d':' -f1 | awk '{printf( "%d\n", $1)}' )
	#min=$(echo $dString | cut -d' ' -f4 | cut -d':' -f2 | awk '{printf( "%d\n", $1)}' )
	isOkDay=$(echo $workDays | grep -c $day)
	if [ $hour -ge 4 ] && [ $hour -le 15 ]; then
		isOkTime=1
	else
		isOkTime=0
	fi
	isOk=$(echo $isOkDay $isOkTime | awk '{printf( "%d\n", $1*$2)}')
	
	if [ $isOk -ge 1 ]; then
		stock_line=$(wget -qO- http://thestockmarketwatch.com/stock/?stock=$SSymbol | grep "$SSymbol</a></td><td class='companyName'>[A-Za-z ,.]*</td><td style=\"width:60px;\"> </td><td style='width:50px;padding:5px;text-align:right;background:rgba([0-9]*,[0-9]*,[0-9]*,[0-9.]*);'>[-0-9.%]*</td><td style='text-align:right;'>[0-9.]*</td><td style='text-align:right;[colred:;]*'>[0-9.%]*</td><td class='hideOnMobile' style='text-align:right;'>[$.0-9kmb]*</td>" -o)
	
		pChange=$(echo $stock_line | grep "background:rgba([0-9]*,[0-9]*,[0-9]*,[0-9.]*);'>[-0-9.]*%" -o | grep -o "[-0-9.]*%$" | grep -o [-0-9.]* | awk '{printf( "%d\n", $1*1000)}' )
		#echo $pChange
		if [ $pChange -le 0 ]; then
			pChangeAbs=$(echo $pChange | grep -o [0-9.]*)
			#echo "its < 0 ... $pChange $pChangeAbs"
			echo $pChangeAbs > $LEDDIR/delay_off
			echo 50 > $LEDDIR/delay_on
		else
			#echo "its > 0 ... $pChange"
			echo $pChange > $LEDDIR/delay_on
			echo 50 > $LEDDIR/delay_off
		fi
	fi	
	#echo "Sleeping for 600 sec..."
	sleep 600
done

Usage

  • Simply pass one argument, the stock symbol.

sh /root/stockled.sh AAPL

Installing as a /etc/init.d service

Lastly, for anyone wanting to install it as a /etc/init.d service, I used this script (given below) located in /etc/init.d

#!/bin/sh /etc/rc.common
USE_PROCD=1
START=99
STOP=01
start_service() {
    procd_open_instance
    procd_set_param command /bin/sh "/root/stockled.sh" AAPL
    procd_set_param stdout 1
    procd_set_param stderr 1
    procd_close_instance
}

You'll want to change the procd_set_param command line to reflect where you placed your initial STOCKLED script and change the stock symbol argument to your stock. You'll also want this file servicename in /etc/init.d to be chmod 777 before enabling the service with:

chmod 777 /etc/init.d/servicename
/etc/init.d/servicename start
/etc/init.d/servicename enable

Ethical Concerns

Network service admins generally hate OpenWRT users using their services in a while loop, so we should be mindful of the number of times we request stock quote data per day. I've set the sleep timer between data requests to 600s (10m) during market/premarket hours to keep the number of data requests down to 72/day which seems reasonable to me for a non-https static webpage displaying live data (i.e. I'd end up refreshing the page > 72 times a day anyway). That said, please be careful if you intend to change these values.

Future Work / Improvements

While it's true we wait 600s (10m) between stock quote requests, this version of the script also waits 600s (10m) before checking the date/time to know if the market is open or not. This leads to 144 /bin/date calls per day. We could reduce this by actually calculating the time until the market opens (if its closed) and act accordingly by sleeping the exact calculated time rather than the current approach.

Conclusion

I hope this is helpful to someone. I enjoy being able to wake up (or roll over in bed @ 4:30am CDT) and glance at my router to know how my stock is doing even if its during the premarket because the regular market hasn't opened yet--if I had more LEDs, I could diversify! #notinvestingadvice

1 Like

Just from a convenience point of view, wouldn't an esp8266 (or RPi-0w) with some kind of LED strip (similar to a bargraph) be a better solution to this problem?

Something like (or even simpler)

Sure -- I even have an Odroid C1+ (Raspberry Pi clone by HardKernel) sitting right below my HT-TM02 (seen in the demo video), but don't have the display on hand to do it.

nice job!
I'd consider doing away with the loop, the time handling and the service and use cron since you're not actually "serving" anything.
You'd instantly regain the resources taken by a shell script running constantly (up to 10% RAM on a small router) and you would be able to only do your calls during the market opening time quite easily with a line like:

*/10 7-19 * * * /root/stockled.sh AAPL

Good point. I considered cron initially, but avoided it because back in my DD-WRT days it was notoriously unreliable ... but here in OpenWRT it's probably fine.