[Devember 2021] [COMPLETE] A telegram bot that notifies you of congress critter stock trades

Of course the house and senate entries are different:

{
	"disclosure_year": 2021,
	"disclosure_date": "10/04/2021",    DD/MM/YYYY
	"transaction_date": "2021-09-27",   YYYY-MM-DD
	"owner": "joint",
	"ticker": "BP",
	"asset_description": "BP plc",
	"type": "purchase",
	"amount": "$1,001 - $15,000",
	"representative": "Hon. Virginia Foxx",
	"district": "NC05",
	"ptr_link": "https://disclosures-clerk.house.gov/public_disc/ptr-pdfs/2021/20019557.pdf",
	"cap_gains_over_200_usd": false
}

{
	"transaction_date": "11/01/2021",
	"owner": "Self",
	"ticker": "PYPL",
	"asset_description": "PayPal Holdings, Inc. - Common Stock",
	"asset_type": "Stock",
	"type": "Sale (Full)",
	"amount": "$250,001 - $500,000",
	"comment": "--",
	"senator": "John W Hickenlooper",
	"ptr_link": "https://efdsearch.senate.gov/search/view/ptr/3ca89f70-6cd2-4b06-a15d-44fd54fc58fa/",
	"disclosure_date": "12/10/2021"
}

Also I found lots of ā€œPDF Filingsā€ which donā€™t contain the data needed, seems kinda dodge.

image

OK got the user DM commands working again, so you can subscribe to specific tickers or congress critters instead of just watching the spam in the broadcast channel. With senators the asset type is listed, e.g. crypto or bonds:

//   COUNT  TYPES OF ASSET
//       3  "Cryptocurrency";
//      20  "Commodities/Futures Contract";
//      97  "Non-Public Stock";
//     203  "Stock Option";
//     237  "Corporate Bond";
//     361  "Other Securities";
//     386  "Municipal Security";
//     465  "PDF Disclosed Filing";
//    6522  "Stock";

So I think Iā€™ll add a thing to watch for those specific types of assets being traded too. Pretty easy to do, but will have to add another section to the readme cos theyā€™ll be subbed like /watch #crypto or /watch #comfuture.

Now onto testing the user subscriptions part.

Conspicuously missing from the list is people like Trump, Biden, Pence, Kamala, Sanders. Pelosi is in there. Not sure whats up with that but oh well :man_shrugging: maybe Iā€™m missing a source.

OK feature complete and running on my Linode at this point. The repo name has been updated, the new link is:

Just to summarize again, there are two modes:

  • broadcast - every trade disclosure is broadcast to a public Telegram channel
  • personalized - talk to the bot and tell it what specific trades you want to know about

It may be hard to judge because of the temporal aspect of this kind of service but nevertheless was fun. I have updated the channel to the ā€œproductionā€ one, but the old one can still be viewed:

And then talking to the bot itself: Telegram: Contact @stonkcritter_bot

Features

image

image

I got it so that you have personal subscriptions by talking to the bot directly. It uses the golang badger DB in the backend to store rep/senator names and subscriptions.

I needed to store the rep senator names, to help make it easier to subscribe. For instance, you can actually type /follow pelosi since sheā€™s the only one in there.

image

It wonā€™t let you subscribe to trade disclosures to unknown reps, since that would be useless. So you can use /critter <name> to find the proper name.

image

When you do a list it shows you them, and has a handy but ugly unfollow link:

image

The subscriptions are quite simple. Just a chat ID and topic. The topic is prefixed with a $ to indicate a ticker. When we find a matching topic, we simply ping the given chatID.

I donā€™t store the disclosures because thereā€™s so many of them, and theyā€™re not really needed beyond the specific timeframe in which the information is useful. Plus I could see scope creep, and that would creep on the stock watcher websites who do a far better job than I could.

I didnā€™t hit my stretch goal of adding types of trades (e.g. stocks or bonds). Most of the code is there but it is not tested (I head on week long 4WD trip tomorrow)

Problems

The data source was tricky to work with, it uses different date formats for some things, and the payload is a bit different between the senate and house data sources.

image

I also had to find, say, every possibility for the asset type field (and how often it occurs). Thanks to gron and the unix philosophy for enabling that.

$ gron all_transations.json|grep asset_type | cut -d'=' -f2 |sort | uniq -c | sort -hk 1
      3  "Cryptocurrency";
     20  "Commodities/Futures Contract";
     97  "Non-Public Stock";
    203  "Stock Option";
    237  "Corporate Bond";
    361  "Other Securities";
    386  "Municipal Security";
    465  "PDF Disclosed Filing";
   6522  "Stock";

Another problem I had was that if you were subbed to Pelosi and AAPL and she traded AAPL you would get messaged twice for the same one. So I made these little deduplicator closures to check you donā€™t get the same message twice:

// deduper is a quick and dirty deduplicator, returns two closures, one to test
// if the given pair is locked, and one to mark the given pair as locked
func deduper() (func(int64, string) bool, func(int64, string)) {
	locks := []string{}

	shouldsend := func(chatID int64, msg string) bool {
		msghash := base64.RawStdEncoding.EncodeToString([]byte(msg))
		lock := strconv.Itoa(int(chatID)) + "_" + msghash
		for _, l := range locks {
			if l == lock {
				return false
			}
		}
		return true
	}

	marksent := func(chatID int64, msg string) {
		msghash := base64.RawStdEncoding.EncodeToString([]byte(msg))
		locks = append(locks, strconv.Itoa(int(chatID))+"_"+msghash)
	}

	return shouldsend, marksent
}

Another one was rate limiting by the Telegram API and I might still be a little conservative with the 1 second delay between disclosure iteration, but I also used a rate limiter from the golang package. I could problem get rid of that 1 second delay.

import "golang.org/x/time/rate"

bot.dmLimit = *rate.NewLimiter(rate.Every(time.Minute/59), 1

// use like this
bot.dmLimit.Wait(context.Background())

Third party software

This is the most relevant libs that I pulled in:

11 Likes

Just pushed all the disclosures for december 2021 to fill the channel with examples. If youā€™re in there you may want to set channel on mute.

1 Like

Did a major refactor, but didnā€™t merge it yet, since the judging is probably gonna go on for a while. So the refactor is just sitting in this PR Refactor: Separate concerns and simplify classes by penguinpowernz Ā· Pull Request #1 Ā· penguinpowernz/stonkcritter Ā· GitHub

I used the concepts of sinks, so alongside Telegram channel and telegram subscription sinks, there are also sinks for:

  • NATS
  • MQTT
  • Websockets

Then it can be plumbed into something like node-red

Iā€™m not sure if the bot is actually delivering updates to itā€™s channels or not, it may not actually be working :frowning:

Hopefully Iā€™ll deploy the new code soon, I need to check up on the judging criteria.

3 Likes

This is such a great project :rofl: Well done :+1:

2 Likes

I am glad you got this completed, and its nice to see you put in a refactor PR on your own project too.

I am not 100% sure, but you should get something for doing this project, even if its only an honourable mention (there were a suprisingly large number of projects by the end of December), after all according to LevelOneNews following congress critter stock trades will have you up at least 10%, so using the channel bot will ā€œmake you moneyā€.

(well thats just my opinion anyway)

Thanks for taking the time to put this project together. Hope you found it useful/profitable.

Cheers

Paul

4 Likes

Thanks guys,

I merged the PR, but the entry commit is tagged with v1.0.0

3 Likes

I assume u could pipe this to home assistant as a sensor using the mqtt polling for latest change of a particular Rep.? Then could use any notification medium from there be it email, matrix, telegram, mattermost, etc.etc

Exactly, yep. Thats why I came back and added the NATS/MQTT etc

1 Like

I had another idea, for the personalized subscriptions, you could ask for a daily/weekly/monthly report, based on the disclosure date, or the transaction date. So you could see something like:

Here's your report for the week ending 28 Jan 2022:
MS        4 buys, 1 sell
Z         4 buys, 4 sells
QCOM      3 buys
ATVI      2 sells

It would just show any ticker that was traded. Problem is of course the trade can be disclosed up to 45 days after the transaction but it may still be useful for informing trade decision.

Keeping tabs on Congress critter stock trades is an interesting idea. Using Golang is a great choice for this kind of bot, given its performance.