In the first part, we examined the basic idea: a trading advisor is not a “robot that trades for you,” but a system that receives market data, generates a signal (and explanation), and shows the result to a person.
We went through the minimal architecture: quotation module → prompt assembly → calling the model → saving the result → web interface and notifications. And we separately noted the optional context layer - news that can be added to the prompt in the form of a summary.
In the second part there will be less “in general” and more practice: what data is really needed at the start, where the nuances of exchange APIs come out, what to store in the database, how not to fall into limits, and why without cache, logging and restrictions, your adviser will fall apart exactly when you count on it.
What data to take at the start
At the start, you have three main classes of market data that can be received from the exchange via the API. The most understandable and common is OHLCV candles: Open/High/Low/Close plus volume per interval. This is a “compressed” representation of the price, which is convenient to store, cache and transfer to the model as a stable piece of context (for example, the last N candles of the selected timeframe1).
If you need to see what is happening inside a candle, connect a trades tape (trades / tape) - the flow of actual executions: price, quantity, time (sometimes side). This layer adds detail to activity and impulses and is typically used as a grainier source than candlesticks.
The third option is order book (order book): bid/ask levels and volumes at each level. This is data about microstructure and liquidity: not “what happened,” but “what is in line now.” It is usually taken as a separate layer of context when it is necessary to take into account market depth, supply/demand imbalance and reaction to levels.
For now, let's focus on the simplest option - OHLCV candles. In your implementation, you can add both transactions and order book, but the purpose of this article is for informational and educational purposes: to put together a clear framework and not get bogged down in details.
Unified data format and history
As soon as you start getting quotes from more than one place, an unpleasant reality emerges: different sources provide the same data in different formats. Somewhere a candle is an array of numbers, somewhere an object with fields, somewhere the time is in milliseconds, somewhere in seconds, and the names and order of the fields may differ even for “similar” APIs..
If you do not introduce a unified format on your side, the system quickly turns into a set of crutches: each new source brings with it separate parsers, exceptions and “special cases”. Therefore, the module for obtaining quotes almost always requires a common internal format - minimally sufficient for further analysis. For our current level, this is usually: instrument, timeframe1, timestamp2, Open/High/Low/Close and Volume.
We should also talk about historical data. “The current state of the market” is good, but without history you will not be able to expand the analysis, test hypotheses, or even correctly explain to the user why the signal looks the way it does. Therefore, even in a simple implementation, it makes sense to store the history of candles (or be able to quickly load it) and record what data formed the basis of a particular signal.
Rate limits: why is it important
Almost every exchange has restrictions on the frequency of requests - rate limits. The reason is simple: if you let all clients “twitch” quotes endlessly, the API will crash even without DDoS.
In the context of an advisor, this is doubly important. Requests are not executed continuously, but according to a timer - and if you choose the frequency incorrectly or multiply it by the number of instruments, you will very quickly hit the limit. The result is usually the same: 429/ban errors per key, holes in the data and “silence” of the system precisely when the market is moving the most.
The working approach here is pragmatic: calculate the request budget in advance (frequency × tools × data types), cache the results, do not request the same thing twice, and handle limits correctly (backoff/repeat after a pause instead of spamming requests).
Prompt and neural networks: same API, different rules
We've sorted out the data acquisition - now we can move on to the next level: prompts and working with neural networks.
At first glance, this is very similar to requesting quotes: again the API, again frequency restrictions, again you need to think about retries, timeouts and cache. Only instead of “give me a candle” you have a request like “here is the data, here is the context, return the signal and explanation.”
Then the differences begin.. For an exchange, the answer is the data structure; for a model, it is the result of interpretation. Therefore, the prompt becomes a contract, and not just “text”, and it has to be treated in the same way as a data format: versioned, checked, limited and logged.
A moment that greatly simplifies life during integration: in a prompt you can pre-fix the structure of the response. For example, ask the model to return the result strictly in JSON - with fields like signal, confidence and reasons. This is not “magic,” but at least it disciplines the format, and on the application side it makes it possible to automatically parse and validate responses instead of parsing free text.
MCP (Model Context Protocol) is worth a special mention: it is an approach/protocol that helps standardize how models receive context and how external data sources and tools are connected. Even if you currently use direct calls to a specific API, having an MCP-like layer in mind is useful - it disciplines the architecture and makes extensibility easier.
And yes, in the future, the “analyst” does not have to be an external service. If resources and motivation appear, this module can be replaced with your own model (or a pre-trained open source one) without rewriting the rest of the system - provided that the interfaces are initially separated correctly.
Storage: easier than it seems
At this stage, we already have at least two “arrays” of data: market candles and analysis results. And if you look a little forward, a news history (and their summary) will be added, plus saving the model’s prompts/responses for debugging and re-analysis. In other words, there is quite a lot of data, and it appears in different places in the pipeline.
Therefore, it makes sense to think about unified storage in advance. The specificity of such data often makes it possible not to drag out a full-fledged SQL schema: in many cases, an embedded database and a simple key-value approach are enough.
KV storage (key-value) is a model where data is stored as “key → value” pairs: using the key you can quickly retrieve the desired object (for example, candles for an instrument and timeframe1 for a period, or the result of an analysis for a specific request)..
Interface: the minimum without which the advisor is useless
And finally - the interface. We’re not going into UI/UX right now, but let me remind you of the basic idea from the first part: at a minimum, you need a web interface, and as a nice addition, notifications in Telegram.
On a practical level, the user only needs a few things. First, see current signals and alerts (and quickly understand what is “happening now”). Secondly, be able to request analysis on demand - get the latest data and signal in one click. And thirdly, configure the system: select tools and data sources, manage API keys, and - what is important - edit prompts and analysis parameters without getting into the code.
Core: the “ring” that connects everything
Tolkien had “one ring to rule them all... and bind them in the dark.” The architecture of the advisor also has this ring - only without pathos: the core of the system, which holds all the modules together.
The kernel is not responsible for analysis as such, but for the lifecycle: application start/stop, dependency initialization, task scheduler, request routing (on demand and on schedule), and correct shutdown. It is here that it is decided what is launched and when, where data is written, and how components communicate with each other without turning into a tangle.
If you want to add new sources of quotes, change the LLM provider, connect news and not rewrite everything every time, the core should be simple but strict: modules - by interfaces, dependencies - explicitly, configuration - centralized, and life cycle - predictable.
At this point you can stop and honestly say: the “skeleton” of the adviser is already visible. Data arrives, the prompt is collected, the model responds, the result is saved and shown to the user - and all this rests on the kernel, which manages the life cycle. In the next article I will go down one level: we will look at the technical details of the implementation - what a unified interface of quote sources looks like, how to arrange a cache and retrays, where to store history, how to validate model responses (including the JSON format), and what to do so that the system does not break due to limits, time and “rare” errors..
Footnotes
- Timeframe is the duration of one candle (data aggregation interval): for example, 1m, 5m, 1h, 1d. It determines exactly how the price flow in OHLCV is “compressed”.
- Timestamp is the timestamp (usually in UTC) that the candle/trade is associated with. A classic mistake: mixing up seconds and milliseconds (or local time and UTC), after which the data “shifts” and the analysis breaks down.
According to itprolab.dev
You May Also Like
EthBackNode: why does your application need a “spacer” between it and the Ethereum node
If you have ever tried to write a crypto-wallet, a payment gateway, or simply a “backend that can send and receive ETH,” then an unpleasant thing quickly becomes clear: the Ethereum node is not your backend
Golang in crypto: when speed and predictability are more important than fashion
If you've ever launched a campaign that “did everything right,” and the site suddenly started to slow down at its peak, you already understand where the conversation about a development language comes from. At such moments, an unpleasant thing becomes clear...
