FinLearn
Archived
Hackathon · Web

FinLearn

Co-developer · 2023

Virtual stock-trading game teaching teenagers market basics: real symbol data, fake wallet. Rather than own the price, the PHP/MySQL web app sends symbol lookup to Alpha Vantage's free tier and lets TradingView embeds draw every chart, then runs registration with credential verification, buy/search flows, holdings seeded from a 10,000 starting balance, expense tracking and learning pages on top. A Java Android client was started and never got past the generated scaffold.

Built with
PHPPHP
MySQLMySQL
JavaScriptJavaScript
HTMLHTML
CSSCSS
Alpha Vantage
TradingView
JavaJava
AndroidAndroid
Project Details

STATUS
Archived
ROLE

Co-developer

YEAR

2023

TYPE

Hackathon · Web

TAGS
FinTech
Education
Gamification

Teenagers get told to learn about the stock market and then handed nothing to practise on. FinLearn was a virtual-money trading game built for that gap: real symbol data, fake wallet, a portfolio you can actually lose. The web app is PHP and MySQL with no framework anywhere, which turned out to be a useful constraint because everything had to be written out by hand.

The hard part of a paper-trading app is not the arithmetic, it is that you need live market data and you do not have a market data budget. FinLearn's answer was to stop trying to own the price. Symbol lookup goes to Alpha Vantage's free tier, and every chart on the site is a TradingView embed — ticker tape and market overview on the stocks screen, symbol info, technical analysis and an advanced chart on the trade screen. The application owns the wallet, the holdings and the user; the numbers on the glass belong to somebody else. That is the right trade for a hackathon build, and it also draws the boundary of what the code actually does.

The two tables

The schema is small enough to describe in a sentence. students holds username, first and last name, email, phone, a password column, a user_state string and a wallet_balance that every new account is seeded with at 10,000. stocks holds username, symbol, quantity, purchase price and a stock_gain column. Positions are rows, not aggregates, so buying the same symbol twice leaves two rows; nothing ever merges them, and nothing ever deletes one.

What it does

  • Registration with field-level validation. register_user.php runs each field through its own checker and returns a JSON map of {val, err} per field, so the client paints inline errors next to the specific input instead of showing one generic failure banner. The rules are hand-written regexes: alphabetic names, a full RFC-ish email pattern, a ten-digit phone check, and a password requiring lower case, upper case, a digit and a symbol.
  • Login with error rehydration. A failed attempt writes the error into sessionStorage and redirects back to the login page, which reads it on load — the only way to carry a message across a redirect when nothing on the server keeps state.
  • Live symbol search. The stocks screen queries Alpha Vantage SYMBOL_SEARCH on keyup and renders an autocomplete list of matching companies, with a server-side equivalent in search_stock.php intended for the same lookup.
  • Trade screen reached with the symbol, company name and exchange passed through the query string, so a search result links directly into the buy flow, with a quantity stepper beside the chart.
  • Buying through buy_stock.php: it reads the wallet balance, refuses the order if the position costs more than the balance, writes the holding, then debits the wallet.
  • A top bar that stays current. Name and wallet figure are refreshed from update_local_storage.php and cached in localStorage, so every page load does not re-query.
  • Holdings, expense tracking, learn and news rounding out the education side — the news page is a TradingView timeline feed, the learn page an embedded video.

The Alpha Vantage hack

Alpha Vantage returns keys like "1. symbol" and "2. name", which are awkward to consume. Rather than quoting them everywhere, the client fetches the response as text and walks it character by character, dropping any N. prefix it finds before handing the result to JSON.parse. The parsed object then has clean symbol and name keys. It is a blunt fix and it would corrupt any legitimate value shaped like "3. ", but it made the rest of the page readable.

The same file has a subtler problem. get_stock_exchange fires an AJAX call and returns from inside the success callback, so the outer function always returns undefined — the exchange parameter that reaches the trade screen is a placeholder. And the search fires on every keystroke past the first character with no debounce, against a free tier metered per minute.

Honest state

Archived, and reading it back there is a list.

Passwords are not hashed. create_user inserts whatever came off the form straight into a column named psw_hash, and login compares the submitted string against it, so the column name is the only hashing in the system. Every query is built by string interpolation, including the login query that interpolates the password, and the database credentials sit in database_connect.php in the repository.

buy_stock.php takes the email, symbol, quantity and price from $_GET and trusts all of them, so the price of a trade is whatever the client says it is. In practice the client does not even pretend: the Buy button on the trade screen is an onclick with a hardcoded query string — one fixed account, one fixed symbol, five shares at a fixed price. The Sell button next to it has no handler at all, and there is no sell path on the server either, so a portfolio can only ever grow.

The holdings and expense pages are static markup. The invested figure, the current value and the P&L on the holdings screen are literals in the HTML, and the expense tracker's two transaction cards and its Add button are the same. Only the name and wallet balance in the top bar come from the database. The server-side search endpoint echoes a variable it never assigns. The password validator enforces 8 to 15 characters while the error message it returns says 7 to 16, which nobody noticed because the message only ever appears when you have already failed. Two vendor API keys are hardcoded into client-side JavaScript.

The Android client, package com.hacktu.finlearn, never got past the generated scaffold: MainActivity sets a layout and get_stocks_json is an empty class. The web app was deployed to free shared hosting and demoed; the phone app was an intention.

Project Details

STATUS
Archived
ROLE

Co-developer

YEAR

2023

TYPE

Hackathon · Web

TAGS
FinTech
Education
Gamification