91f6f67257
The first language stecker on the C ABI hub: a .NET binding exposing all 514 indicators as idiomatic `IDisposable` classes, generated from `wickra.h`. ## What's here - **`bindings/csharp/`** — the `Wickra` .NET 8 package. `[LibraryImport]` source-generated P/Invoke (`NativeMethods.g.cs`) plus idiomatic wrappers (`Indicators.g.cs`), both generated from the committed `bindings/c/include/wickra.h`. The binding owns no indicator maths — it only marshals types across the C ABI. - **Marshalling, verified end-to-end against the native library.** Opaque handles cross as `nint` kept alive per call via a `SafeHandle`; `bool` as `[MarshalAs(U1)]` (Rust `bool` is one byte); a self-correcting `DllImportResolver` validates the loaded library actually exports the Wickra ABI. Tests cover one representative per FFI archetype (scalar, candle, pairwise, multi-output, bars, profile, values-profile, order-book / array-input) plus exact Sma reference values. - **NuGet packaging** — `dotnet pack` produces `Wickra.<version>.nupkg`; the release pipeline stages prebuilt native libraries under `runtimes/<rid>/native/` for six target triples (win/linux/osx × x64/arm64). - **`examples/csharp/`** — nine examples mirroring `examples/c/`: streaming, backtest, multi_timeframe, parallel_assets, three strategies, and fetch_btcusdt + live_binance. - **CI** — a `csharp` job on the three OSes builds the C ABI, tests the binding, and runs the offline examples. **Release** — a gated `csharp-publish` job packs and pushes to NuGet (gated on `NUGET_API_KEY`, independent of the GitHub-release job so a C# hiccup never blocks the C/C++ asset release). - **Docs consistency wave** — README, CONTRIBUTING, CHANGELOG, examples/README, the issue / PR templates, `sync-about.yml`, and `.gitattributes`. The native Python / Node / WASM bindings and the C ABI are untouched; this is additive. Publishing to NuGet stays gated behind the release tag and the secret.
34 lines
1.2 KiB
C#
34 lines
1.2 KiB
C#
using System.Globalization;
|
|
using System.Text.Json;
|
|
|
|
// Download real BTCUSDT hourly klines from the Binance REST API into a CSV that the
|
|
// other examples can consume. Requires network access (build-only in CI).
|
|
const string url = "https://api.binance.com/api/v3/klines?symbol=BTCUSDT&interval=1h&limit=500";
|
|
|
|
using var http = new HttpClient();
|
|
Console.WriteLine($"Fetching {url}");
|
|
var json = await http.GetStringAsync(url);
|
|
|
|
using var doc = JsonDocument.Parse(json);
|
|
var dir = Path.Combine(AppContext.BaseDirectory, "data");
|
|
Directory.CreateDirectory(dir);
|
|
var path = Path.Combine(dir, "btcusdt_1h.csv");
|
|
|
|
using var writer = new StreamWriter(path);
|
|
writer.WriteLine("timestamp,open,high,low,close,volume");
|
|
var count = 0;
|
|
foreach (var kline in doc.RootElement.EnumerateArray())
|
|
{
|
|
// Binance kline array: [openTime, open, high, low, close, volume, ...]
|
|
var ts = kline[0].GetInt64();
|
|
var o = kline[1].GetString();
|
|
var h = kline[2].GetString();
|
|
var l = kline[3].GetString();
|
|
var c = kline[4].GetString();
|
|
var v = kline[5].GetString();
|
|
writer.WriteLine(string.Create(CultureInfo.InvariantCulture, $"{ts},{o},{h},{l},{c},{v}"));
|
|
count++;
|
|
}
|
|
|
|
Console.WriteLine($"Wrote {count} klines to {path}");
|