G-Research Crypto Forecasting
My first pass at a quant competition, from minute bars to a leakage-aware forecasting baseline
This was my first real attempt at a quant competition, and my first time working with market data that moves every minute. I expected the interesting part to be choosing a machine-learning model. It was not. The difficult part was working out what the model could know at each moment and being honest about what a score does, and does not, show.
G-Research Crypto Forecasting asks for a prediction of a future crypto-market return from information available at the current minute. I began with the public Cryptocurrency Extra Data - Cardano mirror because it made the shape of the data easier to understand. That was a useful smoke test, but not the finished experiment. The result below now comes from the canonical original 14-asset competition archive.
First, the vocabulary I had to learn
The source gives one row per asset per minute. These are the terms I wish I had before starting:
- OHLCV means open, high, low, close, and volume. It is the compact record of what happened in a market during one minute.
- A feature is information the model can see now, such as a recent price change, unusual volume, or the shape of the current candle.
- The target is the future value I want to predict. It must never become an input feature, even indirectly.
- Pearson correlation measures whether predictions and targets move together.
1is perfectly aligned,0has no linear relationship, and a negative value points in the wrong direction. - Weighted Pearson is the same measure while giving each asset the importance specified by the competition's official asset weights. It stops a thinly traded asset from counting exactly the same as every other asset.
- Leakage is accidentally letting future information influence the past. It can make a result look impressive and then disappear in a real setting.

How to read this chart: time runs left to right in UTC. The blue line is the last traded price at each recorded minute. The green middle panel is trading volume: tall spikes mean much more Cardano changed hands during that minute than usual. The orange line is not the price. It is the future-return target, so values above zero mean the later return was positive and values below zero mean it was negative. The broken sections matter because the source did not provide a minute there, and I did not draw a fake line across the gap.
My basic reading order is: read the x-axis first, check the units on each y-axis, find the zero line when there is one, then look for changes rather than one dramatic point. The three panels use different scales, so a tall volume spike does not mean the price moved by the same amount. A chart can suggest a question to test; it cannot prove the answer.
From smoke test to official data
The Cardano-only run taught me how to build timestamp-safe features, but it could not reproduce the competition setup. The original archive contains 14 assets and their official weights, so I switched to that source rather than mixing several reconstructed datasets.
For a reproducible first full run, I took the final 180 days of the archive: 3,627,788 rows across all 14 assets. I used 20 price, volatility, volume, candle, time-of-day, and cross-asset features. The model is LightGBM, a gradient-boosted tree model that can learn nonlinear combinations of those inputs without requiring a deep-learning stack.
One detail I nearly missed: a five-row lag is not necessarily a five-minute lag. Market feeds can have missing minutes. The feature code checks the timestamp at every requested lag and leaves a value missing when the data jumps. The model can handle that missing value, but it never gets to pretend the gap was a normal observation.
How I checked it
I did not randomly shuffle the data. That is normal in many ML problems, but wrong here: shuffled rows would let the model learn from a future market regime and then call it validation.
Instead, I held out the latest 543,876 rows completely and used the earlier 3,081,619 rows for development. Within that development period, I chose the model using two expanding validation folds: train on an early span, validate on the next span, then move forward. I also leave a 16-minute embargo at each boundary. Because the target looks into the future, the embargo stops a training label from reaching into the period where validation begins.
The pipeline scores every model and baseline on exactly the same valid rows with official asset weights. It refuses to silently drop invalid predictions or zero weights, because that can make a broken model look better than it is. It also saves the fitted model, input checksum, package versions, feature list, score table, and report image.

How to read this report: the bars on the left compare the two LightGBM configurations during model selection. Higher is better because a larger positive weighted Pearson means predictions lined up more often with later targets after applying the official asset weights. I treated Asset_ID as a categorical input, so the model can learn asset-specific patterns without pretending that the numeric asset labels have a natural order. I selected the configuration with the higher mean across the two chronological folds: 0.02298045.
The line on the right breaks the untouched final-holdout score into individual days. The horizontal zero line is the key reference: days above it had a positive local relationship between predictions and later targets; days below it did not. The day-to-day fluctuation is a warning, not a live edge. A positive aggregate correlation is not a return, a probability, or permission to trade. It is evidence from this fixed historical evaluation, and it needs further tests before any claim about a live strategy.
The official result
After selecting the configuration only on the two development folds, I trained it on all 3,081,619 development rows and evaluated the 543,876 rows that had remained untouched. The final weighted Pearson was 0.04855914. The matched-coverage naive one-minute-return baseline was -0.00786728.
That is a meaningful improvement over the naive baseline in this experiment, not proof that I found a profitable trading strategy. Costs, execution, changing market regimes, and further untouched periods all matter. The important improvement over my first Cardano smoke test is not just the number: the result now uses the original 14-asset archive, the competition weights, chronological selection, an embargo, and a genuinely untouched final window.
What I learned
The model is the smallest part of the work. The useful habits were:
- make the naive baseline fail before celebrating a complicated model;
- write down exactly when a feature becomes available;
- validate in chronological order;
- keep gaps in the data visible instead of smoothing them away;
- treat a score as evidence with limits, not a claim that a strategy will make money.
The repository has the canonical archive downloader, reproducible 180-day data preparation, feature code, strict metric checks, tests, saved artifacts, and reproduction commands. For a first quant project, getting those foundations in place taught me more than changing models ever could.