Skip to main content

Featured

Single Buy vs. Genuine Cluster

Insider buying alerts get treated as a single, uniform signal, but a single purchase and a genuine cluster of independent purchases carry very different informational weight — and the distinction is checkable in public filings well before it becomes a headline. The Surface Issue Stock-screening tools flag "insider buying" whenever any officer or director makes an open-market purchase, with no distinction between a routine, isolated transaction and a genuinely unusual pattern. That flattening is what makes the raw alert an unreliable signal on its own. The Structural Cause Insiders buy shares for reasons that often have nothing to do with a near-term view on the stock — personal financial planning, routine plan participation, diversification timing. A single purchase can't be distinguished from these ordinary reasons. Multiple, independent insiders buying within a short window is much harder to explain away as coincidence or routine planning. 144TICKJOURNAL · TR...

How I Connected Flutter to Firebase to Build a Real-Time Trading Signal Display — A Plain-English Explanation

 

If you've ever watched a stock ticker or a sports scoreboard update live on your phone without you pressing refresh, you've already experienced what Firebase Realtime Database does. Data changes somewhere, and your screen updates almost instantly. That's the core technology behind the NanoRich signal display app, and this post explains exactly how it works — in plain language, without assuming you already know what any of these terms mean.


What "Real-Time" Actually Means in a Mobile App


Most apps work like a waiter taking your order. You ask for something ("give me the menu"), the kitchen prepares it, and the waiter brings it back. You ask, you wait, you receive. This is called a request-response pattern.


Real-time apps work differently. Instead of asking every few seconds "has anything changed?", your app establishes a standing connection to a data source and says "tell me the moment anything changes." The data source then pushes updates to your app the instant they happen — without you asking. This is called a push model or event-driven architecture.


Firebase Realtime Database is built on this push model. When data in the database changes, Firebase automatically notifies every connected app or device that is listening to that data path — usually within a fraction of a second. This is why the NanoRich dashboard can show a signal update within moments of the Python trading engine writing it to the database, without the app constantly polling for new data.


The Three-Part System Behind the App


Before explaining the Flutter code, it helps to understand how the three pieces of the system fit together.


The first piece is the Python trading engine running on a desktop computer. This program connects to the brokerage API, receives real-time stock data, runs the signal detection logic, and writes results to Firebase when a signal event occurs. This piece is always running during Korean market hours.


The second piece is the Firebase Realtime Database — a cloud-hosted database managed by Google. Think of it as a shared whiteboard in the cloud. The Python engine writes on the whiteboard. The Flutter app reads from the whiteboard. Firebase is the intermediary that makes this possible without the two systems needing to know how to communicate directly with each other.


The third piece is the Flutter app on the user's phone. This piece reads from the Firebase whiteboard and displays the information in a clear, mobile-optimized format. Critically, it also watches for changes — the moment something new is written to the whiteboard, the app's screen updates automatically.


Setting Up Flutter to Read From Firebase


Adding Firebase to a Flutter project starts with installing a package. Flutter uses a package system similar to how you'd add a plugin or extension to any software — you declare the dependency and the system installs it. For Firebase Realtime Database in Flutter, the relevant package is called firebase_database, and it's part of the FlutterFire collection of packages maintained by Google.


Once the package is installed, connecting to the database requires three things: a Firebase project (created in the Firebase Console at console.firebase.google.com), a configuration file that tells your Flutter app which Firebase project to connect to, and initialization code that runs when the app starts.


The configuration file — called google-services.json on Android — is downloaded from the Firebase Console and placed in a specific folder in the Flutter project. This file contains the project ID, database URL, and API keys that the Firebase SDK needs to find and authenticate with the correct database. It is not a secret file in the sense that it needs to be kept away from users, but it should not be shared publicly because it could allow someone to read data from your database if the security rules aren't properly configured.


The initialization code runs once at app startup and looks roughly like this in Dart, Flutter's programming language:


await Firebase.initializeApp(

  options: DefaultFirebaseOptions.currentPlatform,

);


This single line initializes the Firebase connection using the settings from the configuration file. After this runs, the rest of the app can access Firebase services including the Realtime Database.


Listening for Real-Time Updates


The part of the code that makes the display update in real time is a listener — a piece of code that tells Firebase "watch this location in the database and call me every time anything changes there."


For the NanoRich app, the location being watched is the path in the database where the Python engine writes signal data. In Firebase, data is organized like a folder structure. The signals for tracked stocks live at a specific path — something like /signals — and each stock has its data nested under that path using its stock code as the key.


The listener code in Flutter looks like this in concept:


FirebaseDatabase.instance

  .ref('/signals')

  .onValue

  .listen((event) {

    // This code runs every time the data at /signals changes

    final data = event.snapshot.value;

    // Update the app's display with the new data

  });


The key piece is onValue — this creates a stream that emits a new event every time the data at the specified database path changes. The listen method attaches a function that runs each time that event fires. Inside that function, you access the new data through event.snapshot.value and use it to update what the app displays.


In Flutter's widget system, the way this connects to the visual display involves a concept called state management. When new data arrives from Firebase, the app needs to rebuild the relevant parts of its display. Flutter's StreamBuilder widget handles this elegantly — it listens to the Firebase stream automatically and rebuilds the widget tree whenever new data arrives, without requiring additional code to trigger the visual update.


The Nested Problem — Handling a List of Stocks


One challenge specific to the NanoRich app's data structure is that the /signals path contains multiple stocks simultaneously, not just a single value. When the Python engine is tracking twelve stocks at once, the database has twelve separate entries under /signals, each with its own set of values (grade, stage, trading value, confirmation time, etc.).


When Firebase sends an update because one stock's data changed, it sends the entire /signals snapshot — all twelve stocks, not just the one that changed. The app code needs to parse this snapshot, extract each stock's data, and build a list of display cards from it.


This parsing step involves iterating through the snapshot's children, converting each child's data from the raw Map format that Firebase delivers into a typed object that the rest of the app can work with cleanly. Getting this conversion right — especially handling the cases where a value might be null if a stock is in an early stage and some data fields haven't been populated yet — is one of the more detail-oriented parts of the implementation.


What Happens When the Database Is Empty


One specific behavior that the app needs to handle gracefully is the state between 15:30 (when the Python engine clears all signal data) and the next morning's session. During this window, the /signals path in the database is empty. The app needs to display a "no signals — market closed" state rather than showing a blank screen or an error.


This is handled by checking whether the snapshot returned by Firebase has any children. If it does, display the signal cards. If it doesn't, display the closed-market message. This check also runs at app startup for users who open the app outside of market hours, and it's important that it happens before attempting to parse the data — trying to iterate through an empty snapshot's children will produce errors if the code assumes the snapshot always contains data.


Today's Investing Insight — What Is a NoSQL Database?


Firebase Realtime Database is a type of database called NoSQL — which stands for "not only SQL" (though it's commonly understood as "not SQL"). Traditional databases, called relational databases, store data in tables with rows and columns, similar to a spreadsheet, and use a language called SQL to query them. NoSQL databases take a different approach: instead of tables, they use other structures — Firebase uses a tree-structured JSON format, similar to how data is organized in modern web APIs. NoSQL databases are generally faster for certain types of operations, particularly when data needs to be retrieved and updated in real time, because their structure avoids the join operations that relational databases need for complex queries. The trade-off is that NoSQL databases provide less rigorous guarantees about data consistency and relationships between pieces of data. For a use case like the NanoRich signal board — where the key requirement is fast, real-time updates rather than complex relational queries — a NoSQL real-time database like Firebase is a natural fit.


---


This post documents a personal journey of building a mobile application and explains general concepts in plain language. Code examples are simplified for readability and are not intended as production-ready implementations. All investment decisions and their outcomes are the sole responsibility of the investor.

Comments