Skip to content

fix(cex-market-data): coingecko ohlc parsing#203

Merged
CharlVS merged 3 commits intodevfrom
bugfix/coingecko-ohlc-parsing
Aug 22, 2025
Merged

fix(cex-market-data): coingecko ohlc parsing#203
CharlVS merged 3 commits intodevfrom
bugfix/coingecko-ohlc-parsing

Conversation

@takenagain
Copy link
Copy Markdown
Contributor

@takenagain takenagain commented Aug 21, 2025

Fixes CoinGecko OHLC parsing with a freezed union type. The Binance and CoinGecko OHLC responses require different structures and parsing, which prevented the CoinGecko API from filling in the gaps.

Before:

image

After:

image

Summary by CodeRabbit

  • New Features

    • Higher-precision OHLC pricing using decimals for improved accuracy across exchanges.
    • Consistent millisecond timestamps for OHLC close times.
    • Source-aware OHLC parsing to distinguish data provenance (e.g., Binance vs. CoinGecko).
  • Refactor

    • Unified OHLC model with cross-source compatibility and serialization.
  • Improvements

    • Price retrieval and sparkline generation now use precise close values without string parsing.
  • Style

    • Minor error message formatting adjustments.
  • Tests

    • Updated tests to reflect decimal pricing and source-specific OHLC construction.

coingecko ohlc format differs to the binance format, so use a freezed union type and convert all values to decimal to standardise
@takenagain takenagain added this to the KW 0.10.0 milestone Aug 21, 2025
@takenagain takenagain self-assigned this Aug 21, 2025
@takenagain takenagain added the bug Something isn't working label Aug 21, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Aug 21, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Introduces a union-based OHLC model with Decimal fields and source tagging, updates Binance/CoinGecko providers to pass OhlcSource to CoinOhlc.fromJson, and adjusts repositories/sparkline and tests to use closeTimeMs/closeDecimal and Ohlc.binance constructors. Adds generated Freezed and JSON serialization files for the new model.

Changes

Cohort / File(s) Summary
OHLC model overhaul
packages/komodo_cex_market_data/lib/src/models/coin_ohlc.dart, .../coin_ohlc.freezed.dart, .../coin_ohlc.g.dart
Replaces legacy Ohlc with Freezed union (CoinGeckoOhlc, BinanceOhlc), adds OhlcSource enum, Decimal-based fields, uniform getters, fromJson/fromKlineArray factories, and generated serialization/copyWith/pattern-match support. CoinOhlc.fromJson now accepts optional/named source.
Binance data path
packages/komodo_cex_market_data/lib/src/binance/data/binance_provider.dart, .../binance_repository.dart
Provider passes source: OhlcSource.binance to CoinOhlc.fromJson; repository switches to closeTimeMs and closeDecimal, removing string parsing. Minor error-string formatting changes.
CoinGecko data path
packages/komodo_cex_market_data/lib/src/coingecko/data/coingecko_cex_provider.dart, .../coingecko_repository.dart
Provider passes source: OhlcSource.coingecko; repository updates to use closeTimeMs and closeDecimal for date/price extraction.
Sparkline
packages/komodo_cex_market_data/lib/src/sparkline_repository.dart
Uses closeDecimal (to double) for sparkline values; updates constant-data path similarly.
Tests
packages/komodo_cex_market_data/test/binance/binance_repository_test.dart, .../coingecko/coingecko_repository_test.dart
Update fixtures to Ohlc.binance with Decimal prices; adjust calls/verifications reflecting USD defaulting and new OHLC APIs.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor App
  participant Repo as Repository (Binance/CoinGecko)
  participant Provider as HTTP Provider
  participant Model as CoinOhlc/Ohlc

  App->>Repo: fetch OHLC / prices
  Repo->>Provider: request klines/ohlc
  Provider->>Provider: decode JSON
  Provider->>Model: CoinOhlc.fromJson(data, source: binance|coingecko)
  Model->>Model: Ohlc.fromKlineArray(..., source)
  Model-->>Provider: CoinOhlc{ ohlc: List<Ohlc.variant> }
  Provider-->>Repo: CoinOhlc
  Repo->>Repo: use closeTimeMs, closeDecimal
  Repo-->>App: computed prices/map
Loading
sequenceDiagram
  autonumber
  actor App
  participant Spark as SparklineRepository
  participant Model as Ohlc entries

  App->>Spark: fetchSparkline(...)
  Spark->>Model: iterate ohlc list
  Note over Spark,Model: Extract closeDecimal<br/>convert to double
  Spark-->>App: List<double> sparkline
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • smk762
  • CharlVS

Poem

A hop, a skip, through candles I glide,
Decimal dewdrops where prices reside.
Binance or Gecko? I tag as I roam,
Two cozy burrows, one charting home.
With squeaky clean ticks and time well kept,
I nibble the klines—precision adept. 🐇📈

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bugfix/coingecko-ohlc-parsing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@takenagain takenagain requested a review from Copilot August 21, 2025 20:21
@takenagain
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Aug 21, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Refactors OHLC data handling to use a freezed union type that accommodates different data formats between CoinGecko and Binance APIs, standardizing all price values as Decimal types for improved precision.

  • Replaces simple Ohlc class with a freezed union type supporting both CoinGecko and Binance formats
  • Converts all numeric price values from double to Decimal for better precision
  • Adds source hints and getter extensions to abstract format differences

Reviewed Changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/komodo_cex_market_data/lib/src/models/coin_ohlc.dart Converts Ohlc from simple class to freezed union type with CoinGecko and Binance variants, adds Decimal support
packages/komodo_cex_market_data/lib/src/models/coin_ohlc.freezed.dart Generated freezed code for the union type
packages/komodo_cex_market_data/lib/src/models/coin_ohlc.g.dart Generated JSON serialization code
packages/komodo_cex_market_data/lib/src/sparkline_repository.dart Updates to use new closeDecimal getter instead of close property
packages/komodo_cex_market_data/lib/src/coingecko/data/coingecko_repository.dart Updates to use new closeTimeMs and closeDecimal getters
packages/komodo_cex_market_data/lib/src/coingecko/data/coingecko_cex_provider.dart Adds CoinGecko source hint when parsing OHLC data
packages/komodo_cex_market_data/lib/src/binance/data/binance_repository.dart Updates to use new closeTimeMs and closeDecimal getters
packages/komodo_cex_market_data/lib/src/binance/data/binance_provider.dart Adds Binance source hint when parsing OHLC data
packages/komodo_cex_market_data/test/coingecko/coingecko_repository_test.dart Updates test data to use Ohlc.binance constructor with Decimal values
packages/komodo_cex_market_data/test/binance/binance_repository_test.dart Updates test data to use Ohlc.binance constructor with Decimal values

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread packages/komodo_cex_market_data/lib/src/sparkline_repository.dart Outdated
Comment thread packages/komodo_cex_market_data/lib/src/sparkline_repository.dart Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Aug 21, 2025

Visit the preview URL for this PR (updated for commit e07b176):

https://komodo-defi-sdk--pr203-bugfix-coingecko-ohl-okznr5tf.web.app

(expires Fri, 29 Aug 2025 08:10:07 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: 7f9f5ac39928f333b6e8fcefb7138575e24ed347

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/komodo_cex_market_data/lib/src/coingecko/data/coingecko_cex_provider.dart (1)

153-154: Bug: wrong query parameter key for precision

The precision argument is being placed under price_change_percentage, which breaks both parameters.

-      if (precision != null) 'price_change_percentage': precision,
+      if (precision != null) 'precision': precision,
🧹 Nitpick comments (10)
packages/komodo_cex_market_data/lib/src/sparkline_repository.dart (2)

138-141: Avoid string round-trip when converting Decimal to double

Use Decimal.toDouble() to reduce allocations and parse overhead.

-      final data =
-          ohlcData.ohlc
-              .map((e) => double.parse(e.closeDecimal.toString()))
-              .toList();
+      final data = ohlcData.ohlc
+          .map((e) => e.closeDecimal.toDouble())
+          .toList();

188-191: Same optimization for constant-price sparkline conversion

Apply the same Decimal.toDouble() change here for consistency and efficiency.

-    final constantData =
-        ohlcData.ohlc
-            .map((e) => double.parse(e.closeDecimal.toString()))
-            .toList();
+    final constantData = ohlcData.ohlc
+        .map((e) => e.closeDecimal.toDouble())
+        .toList();
packages/komodo_cex_market_data/lib/src/binance/data/binance_repository.dart (1)

164-165: Select the most recent candle; don’t assume .first is “latest”.

If getCoinOhlc returns candles in ascending time (Binance typically does), .first will yield the oldest item in the range, not the current price you want. Prefer .last, or pick by max closeTimeMs to be robust to ordering.

Apply this minimal fix:

-    return ohlcData.ohlc.first.closeDecimal;
+    // Use the most recent candle in the returned range.
+    return ohlcData.ohlc.last.closeDecimal;

If ordering isn’t guaranteed by providers, sort by closeTimeMs first.

packages/komodo_cex_market_data/lib/src/models/coin_ohlc.g.dart (1)

12-16: Decimal parsing path differs from @DecimalConverter; verify JSON shape.

Generated code uses Decimal.fromJson(json['open'] as String) for OHLC prices, bypassing @DecimalConverter. This requires JSON strings, not numbers. If any serialization/deserialization path emits numeric JSON for these fields, it will break.

No change requested in generated code; if needed, force the converter at the source by annotating fields with an explicit @JsonKey(fromJson: DecimalConverter().fromJson, toJson: DecimalConverter().toJson) in coin_ohlc.dart so the generator doesn’t default to Decimal.fromJson.

packages/komodo_cex_market_data/test/coingecko/coingecko_repository_test.dart (3)

30-37: Use the CoinGecko variant in CoinGecko tests for clarity.

You’re stubbing Ohlc.binance inside a CoinGecko repository test. Functionally OK (thanks to the getters), but confusing. Prefer Ohlc.coingecko to match the subject under test.

-            Ohlc.binance(
-              open: Decimal.fromInt(100),
-              high: Decimal.fromInt(110),
-              low: Decimal.fromInt(90),
-              close: Decimal.fromInt(105),
-              openTime: startAt.millisecondsSinceEpoch,
-              closeTime: endAt.millisecondsSinceEpoch,
-            ),
+            Ohlc.coingecko(
+              timestamp: endAt.millisecondsSinceEpoch,
+              open: Decimal.fromInt(100),
+              high: Decimal.fromInt(110),
+              low: Decimal.fromInt(90),
+              close: Decimal.fromInt(105),
+            ),

74-81: Same here: prefer Ohlc.coingecko in CoinGecko tests.

-            Ohlc.binance(
+            Ohlc.coingecko(
+              timestamp: endAt.millisecondsSinceEpoch,
               open: Decimal.fromInt(100),
               high: Decimal.fromInt(110),
               low: Decimal.fromInt(90),
               close: Decimal.fromInt(105),
-              openTime: startAt.millisecondsSinceEpoch,
-              closeTime: endAt.millisecondsSinceEpoch,
             ),

121-128: Consistency nit: use CoinGecko OHLC in CoinGecko tests.

-            Ohlc.binance(
+            Ohlc.coingecko(
+              timestamp: endAt.millisecondsSinceEpoch,
               open: Decimal.fromInt(100),
               high: Decimal.fromInt(110),
               low: Decimal.fromInt(90),
               close: Decimal.fromInt(105),
-              openTime: startAt.millisecondsSinceEpoch,
-              closeTime: endAt.millisecondsSinceEpoch,
             ),
packages/komodo_cex_market_data/lib/src/models/coin_ohlc.dart (3)

39-47: UTC timestamps for synthetic data; also consider Decimal parameter.

  • For synthetic candles, use UTC epoch millis (time.toUtc().millisecondsSinceEpoch) to align with exchange data and downstream UTC grouping.
  • Optional: accept Decimal constantValue directly to avoid parse/format churn.
-          final time = startAt.add(Duration(seconds: index * intervalSeconds));
+          final time = startAt.add(Duration(seconds: index * intervalSeconds)).toUtc();
...
-            openTime: time.millisecondsSinceEpoch,
-            closeTime: time.millisecondsSinceEpoch,
+            openTime: time.millisecondsSinceEpoch,
+            closeTime: time.millisecondsSinceEpoch,

If you want to switch to a Decimal param:

-  factory CoinOhlc.fromConstantPrice({
+  factory CoinOhlc.fromConstantPrice({
     required DateTime startAt,
     required DateTime endAt,
     required int intervalSeconds,
-    double constantValue = 1.0,
+    Decimal constantValue = Decimal.one,
   }) {
...
-            high: Decimal.parse(constantValue.toString()),
+            high: constantValue,
...

Also applies to: 53-61


116-172: Robust array parsing with clear erroring; one minor enhancement.

  • Conversion helpers are defensive and produce actionable errors.
  • Source hint + length heuristic is pragmatic.

Minor enhancement: some Binance-like arrays can be length 12–13+; you already accept >= 11 which is fine. Consider documenting index expectations above the factory (link to API docs) to aid future maintenance.


178-190: Document “closeTimeMs” semantics for CoinGecko variant.

closeTimeMs maps to the same timestamp as openTimeMs for CoinGecko, since their array only carries one timestamp. It’s fine, but deserves a comment to avoid confusion when someone expects distinct open/close times.

Optionally add helpers:

extension OhlcDateHelpers on Ohlc {
  DateTime get closeAtUtc =>
      DateTime.fromMillisecondsSinceEpoch(closeTimeMs, isUtc: true);
  DateTime get openAtUtc =>
      DateTime.fromMillisecondsSinceEpoch(openTimeMs, isUtc: true);
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 868878c and aa81373.

📒 Files selected for processing (10)
  • packages/komodo_cex_market_data/lib/src/binance/data/binance_provider.dart (2 hunks)
  • packages/komodo_cex_market_data/lib/src/binance/data/binance_repository.dart (2 hunks)
  • packages/komodo_cex_market_data/lib/src/coingecko/data/coingecko_cex_provider.dart (1 hunks)
  • packages/komodo_cex_market_data/lib/src/coingecko/data/coingecko_repository.dart (1 hunks)
  • packages/komodo_cex_market_data/lib/src/models/coin_ohlc.dart (4 hunks)
  • packages/komodo_cex_market_data/lib/src/models/coin_ohlc.freezed.dart (1 hunks)
  • packages/komodo_cex_market_data/lib/src/models/coin_ohlc.g.dart (1 hunks)
  • packages/komodo_cex_market_data/lib/src/sparkline_repository.dart (2 hunks)
  • packages/komodo_cex_market_data/test/binance/binance_repository_test.dart (1 hunks)
  • packages/komodo_cex_market_data/test/coingecko/coingecko_repository_test.dart (5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build_and_preview_playground_preview
  • GitHub Check: build_and_preview_sdk_example_preview
🔇 Additional comments (8)
packages/komodo_cex_market_data/lib/src/coingecko/data/coingecko_cex_provider.dart (1)

507-507: Correct: propagate source to CoinOhlc.fromJson

Passing source: OhlcSource.coingecko aligns with the new union model and prevents mis-parsing.

packages/komodo_cex_market_data/test/binance/binance_repository_test.dart (1)

258-268: Ohlc.binance usage matches current factory signature

I’ve confirmed that the test’s named parameters (openTime, open, high, low, close, closeTime) exactly align with the const factory Ohlc.binance({ required int openTime, required Decimal open, required Decimal high, required Decimal low, required Decimal close, required int closeTime, … }) signature in coin_ohlc.dart. The optional fields (volume, quoteAssetVolume, etc.) are not passed in tests, which is valid since they’re nullable. No changes are needed here.

packages/komodo_cex_market_data/lib/src/binance/data/binance_provider.dart (3)

45-49: Correct: tag Binance OHLC JSON with its source

fromJson(..., source: OhlcSource.binance) is required with the new union. Good catch.


51-53: Minor consistency tweak acknowledged

Error message reformatting is fine; preserves content while improving readability.


119-121: Minor consistency tweak acknowledged

Same here for the 24hr ticker path; no functional change.

packages/komodo_cex_market_data/lib/src/models/coin_ohlc.dart (2)

14-24: Parsing by source + heuristic looks good.

Factory now accepts a source hint and gracefully falls back to length-heuristics. This should unblock mixed-provider inputs while keeping strict erroring on invalid shapes.


87-114: Freezed union for OHLC is a solid move.

Clear separation of CoinGecko vs Binance payloads, with snake_case JSON, and Decimal fields for precision. This should simplify downstream logic and serialization.

packages/komodo_cex_market_data/lib/src/models/coin_ohlc.freezed.dart (1)

12-36: Generated Freezed union looks consistent with the source.

Runtime type switching, equality, copyWith, and JSON glue match the declared variants. No manual changes needed.

Comment thread packages/komodo_cex_market_data/lib/src/binance/data/binance_repository.dart Outdated
Comment thread packages/komodo_cex_market_data/lib/src/coingecko/data/coingecko_repository.dart Outdated
@takenagain takenagain marked this pull request as ready for review August 22, 2025 08:09
@takenagain takenagain requested a review from CharlVS August 22, 2025 15:05
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please retain (and update if needed) the public member documentation in this file and (if applicable) all other files touched by this PR.

Otherwise, looks good, thanks.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 3af1ed5

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bugbot free trial expires on August 22, 2025
Learn more in the Cursor dashboard.

ids: ['bitcoin'],
vsCurrency: 'usd', // Should fall back to 'usd', never 'usdt'
),
() => mockProvider.fetchCoinMarketData(ids: ['bitcoin']),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Test Coverage Loss for Stablecoin Mapping

The getCoin24hrPriceChange tests stopped verifying the vsCurrency parameter passed to the provider. This removes coverage for the critical logic that maps stablecoins (like USDT) to their underlying fiat currencies (like USD) and handles fallbacks, meaning a future regression in this mapping might go undetected.

Fix in Cursor Fix in Web

@CharlVS CharlVS merged commit ca288fd into dev Aug 22, 2025
4 of 7 checks passed
@CharlVS CharlVS deleted the bugfix/coingecko-ohlc-parsing branch August 22, 2025 20:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants