Вы должны войти, чтобы создавать сообщения и темы.

Не могу разобраться с json

Страница 1 из 2►

Всем доброго времени!
Пытаюсь что-то сделать на c#...
Есть код, который по API берет информацию: символ/монета и его цена, делает расчёт и редактирует xml файл.

Код

using System;
using System.Linq;
using System.Net;
using System.Collections.Generic;
using System.Web.Script.Serialization;
using System.Windows.Forms;
using System.Xml.Linq;
using System.IO;

namespace Test
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        string url_fut = "https://www.binance.com/fapi/v1/ticker/price";
        string url_exchangeInfo_fut = "https://www.binance.com/fapi/v1/exchangeInfo";

        void calculate_Click_1(object sender, EventArgs e)
        {
            using (WebClient client = new WebClient())
            {
                string json = client.DownloadString(url_fut);
                var serializer = new JavaScriptSerializer();
                int count_fut = 0;

                List<PriceData> prices = serializer.Deserialize<List<PriceData>>(json);

                foreach (PriceData price in prices)
                {

                    #region Переменные
                    string first_WorkAmount = (Convert.ToDouble(value_1.Text) / price.price).ToString();
                    string fileName_fut = $"BINAD.CCUR_FUT.{price.symbol}_Settings_55555.xml";
                    #endregion

                    if (File.Exists(fileName_fut))
                    {
                        XDocument doc = XDocument.Load(fileName_fut);

                        void Descend(string x, string y)
                        {
                            doc.Descendants(x).First().SetAttributeValue("Value", y);
                        }
                        Descend("First_WorkAmount", first_WorkAmount);

                        doc.Save(fileName_fut);
                        count_fut++;
                    }
                    else
                    {
                        continue;
                    }
                }
                MessageBox.Show("Изменён", Text, MessageBoxButtons.OK);
            }
        }
    }
    class PriceData
    {
        public string symbol { get; set; }
        public double price { get; set; }
    }
}


Всё работает как надо, но значение переменной first_WorkAmount слишком сильно дробится. У каждого символа/монеты есть свой "stepSize", который можно узнать по API в переменной url_exchangeInfo_fut. Так вот мне надо как-то округлить значение, которое получается в переменной first_WorkAmount, для каждого символа в соответствии с его размером "stepSize".
Совсем не пойму как это сделать...

Евгений, привет.
Если я правильно понял, имеешь на выходе число 127.118288191, а нужно его сократить до 127.11 напимер?
Если так, то можно

Пример

Скопированоdouble num = 127.11828811; Скопированоdouble cutedDouble = double.Parse(num.ToString("0.00")); СкопированоMessageBox.Show(cutedDouble.ToString());

Лайкнул Евгений
Евгений
Цитата: Никита от 25.01.2023, 16:02

Евгений, привет.
Если я правильно понял, имеешь на выходе число 127.118288191, а нужно его сократить до 127.11 напимер?
Если так, то можно

Пример

Скопированоdouble num = 127.11828811; Скопированоdouble cutedDouble = double.Parse(num.ToString("0.00")); СкопированоMessageBox.Show(cutedDouble.ToString());

Да, сократить надо так, только в соответствии со stepSize, получается монет например 20 штук, у какой-то монеты stepSize 0.1 тогда тогда для неё будет в итоге 127.1, а у какой-то монеты stepSize 0.001 и тогда для неё получится соответственно 127.118. Этот stepSize есть по апи, для каждой монеты stepSize свой и вот как их сопоставить вообще не пойму...

Самое первое, что пришло в голову, но достаточно тупое решение, делать как-то так

double cutedDouble = double.Parse(num.ToString(stepSize.ToString().Replace("1","0")));

Хотя уверен есть и более правильный вариант.

Лайкнул Евгений
Евгений
Цитата: Adler от 25.01.2023, 17:04

Самое первое, и вероятно, самое тупое, делать как-то так

 
 
 
 
double cutedDouble = double.Parse(num.ToString(stepSize.ToString().Replace("1","0")));
double cutedDouble = double.Parse(num.ToString(stepSize.ToString().Replace("1","0")));
 
double cutedDouble = double.Parse(num.ToString(stepSize.ToString().Replace("1","0")));

Хотя уверен есть и более правильный вариант.

Я уверен в том, что stepSize должен присутствовать именно в расчётах вот тут

string first_WorkAmount = (Convert.ToDouble(value_1.Text) / price.price).ToString();

Евгений, если stepSize имеет именно тот формат, что ты написал, то должно работать.

string first_WorkAmount = ((double.Parse(value_1.Text) / price.price)).ToString(stepSize.Replace("1", "0"));
Лайкнул Евгений
Евгений

Только если сам stepSize является числом, а не строкой, то перед этим преобразуй его в строку.

string strStepSize = stepSize.ToString();
string first_WorkAmount = ((double.Parse(value_1.Text) / price.price)).ToString(strStepSize.Replace("1", "0"));
Лайкнул Евгений
Евгений
Цитата: Никита от 25.01.2023, 17:42

Только если сам stepSize является числом, а не строкой, то перед этим преобразуй его в строку.

 
 
 
 
string strStepSize = stepSize.ToString();
string first_WorkAmount = ((double.Parse(value_1.Text) / price.price)).ToString(strStepSize.Replace("1", "0"));
string strStepSize = stepSize.ToString(); string first_WorkAmount = ((double.Parse(value_1.Text) / price.price)).ToString(strStepSize.Replace("1", "0"));
 
string strStepSize = stepSize.ToString();
string first_WorkAmount = ((double.Parse(value_1.Text) / price.price)).ToString(strStepSize.Replace("1", "0"));

@adler, @dvgm, парни, я не на столько умный как вам кажется ))) что мне надо ещё сделать с этим stepSize. Сначала так же загрузить строку

string json_exchange = client.DownloadString(url_exchangeInfo_fut);

Далее десериализовать её

var serializer_exchange = new JavaScriptSerializer();
List<Filter> exchangeInfo = serializer_exchange.Deserialize<List<Filter>>(json_exchange);

Добавить класс

public class Filter
{
    public string stepSize { get; set; }
}

И потом только попробовать ваш вариант

string first_WorkAmount = ((double.Parse(value_1.Text) / price.price)).ToString(stepSize.Replace("1", "0"));

Не судите строго, я совсем новичок, но хочется как-то разобраться )

Всем привет! Вы уверены, что нужно округлять именно по СкопированоstepSize?
Самый первый элемент ответа API в моём случае выдал Скопировано0.02931 для СкопированоIOTXUSDT, но его СкопированоstepSize = 1. Причём, у некоторых символов, он отличается в зависимости от СкопированоfilterType (LOT_SIZE, MARKET_LOT_SIZE, возможно, другие).

Спойлер

Лайкнул Евгений
Евгений
Цитата: Dapofig от 25.01.2023, 19:57

Всем привет! Вы уверены, что нужно округлять именно по СкопированоstepSize?
Самый первый элемент ответа API в моём случае выдал Скопировано0.02931 для СкопированоIOTXUSDT, но его СкопированоstepSize = 1. Причём, у некоторых символов, он отличается в зависимости от СкопированоfilterType (LOT_SIZE, MARKET_LOT_SIZE, возможно, другие).

Спойлер
<img class="lazyload" src="data:;base64," alt="" width="216" height="100" data-orig-src="https://i.imgur.com/YIov5lJ.png" style="color: #25d39d !important" />

<img class="lazyload" src="data:;base64," alt="" width="324" height="650" data-orig-src="https://i.imgur.com/vMiemj2.png" style="color: #25d39d !important" />

IOTX
Всё верно, нужно именно по фильтру (LOT_SIZE, взять значение stepSize = 1). В картинке показал наглядно, видите там написано Шаг=1, цена монеты на это ни как не влияет, в цене может быть много цифр после запятой...

Евгений, я попробую ещё раз уточнить)
first_WorkAmount = какое-то число разделить на какое-то число.
Например (388,11 / 33) = 11.7609090909
Соответсвенно тебе нужно сделать, чтобы first_WorkAmount был равен не 11.7609090909, а например 11.760 (кол-во чисел после точки прописывается в том самом stepSize)
Я верно понял?
Если да, то сначала запиши в Скопированоstring strStepSize = stepSize.ToString();
После чего уже расчитай свой first_WorkAmount так Скопированоstring first_WorkAmount = ((double.Parse(value_1.Text) / price.price)).ToString(strStepSize.Replace("1", "0"));

Лайкнул Евгений
Евгений
Цитата: Никита от 25.01.2023, 21:28

Евгений, я попробую ещё раз уточнить)
first_WorkAmount = какое-то число разделить на какое-то число.
Например (388,11 / 33) = 11.7609090909
Соответсвенно тебе нужно сделать, чтобы first_WorkAmount был равен не 11.7609090909, а например 11.760 (кол-во чисел после точки прописывается в том самом stepSize)
Я верно понял?
Если да, то сначала запиши в Скопированоstring strStepSize = stepSize.ToString();
После чего уже расчитай свой first_WorkAmount так Скопированоstring first_WorkAmount = ((double.Parse(value_1.Text) / price.price)).ToString(strStepSize.Replace("1", "0"));

 
 

 

 

Всё верно first_WorkAmount = число которое ввели в textBox / на цену монеты и округлить результат до stepSize. Цену монеты получаю по первому апи. С этим проблем нет, всё ок работает. Но как мне добраться до stepSize. Там эти все зависимости в строке, которую по апи получаю...

Структура того самого JSON

{
    "exchangeFilters": [],
    "rateLimits": [
        {
            "interval": "MINUTE",
            "intervalNum": 1,
            "limit": 2400,
            "rateLimitType": "REQUEST_WEIGHT" 
        },
        {
            "interval": "MINUTE",
            "intervalNum": 1,
            "limit": 1200,
            "rateLimitType": "ORDERS"
        }
    ],
    "serverTime": 1565613908500,    // Ignore please. If you want to check current server time, please check via "GET /fapi/v1/time"
    "assets": [ // assets information
        {
            "asset": "BUSD",
            "marginAvailable": true, // whether the asset can be used as margin in Multi-Assets mode
            "autoAssetExchange": 0 // auto-exchange threshold in Multi-Assets margin mode
        },
        {
            "asset": "USDT",
            "marginAvailable": true,
            "autoAssetExchange": 0
        },
        {
            "asset": "BNB",
            "marginAvailable": false,
            "autoAssetExchange": null
        }
    ],
    "symbols": [
        {
            "symbol": "BLZUSDT",
            "pair": "BLZUSDT",
            "contractType": "PERPETUAL",
            "deliveryDate": 4133404800000,
            "onboardDate": 1598252400000,
            "status": "TRADING",
            "maintMarginPercent": "2.5000",   // ignore
            "requiredMarginPercent": "5.0000",  // ignore
            "baseAsset": "BLZ", 
            "quoteAsset": "USDT",
            "marginAsset": "USDT",
            "pricePrecision": 5,    // please do not use it as tickSize
            "quantityPrecision": 0, // please do not use it as stepSize
            "baseAssetPrecision": 8,
            "quotePrecision": 8, 
            "underlyingType": "COIN",
            "underlyingSubType": ["STORAGE"],
            "settlePlan": 0,
            "triggerProtect": "0.15", // threshold for algo order with "priceProtect"
            "filters": [
                {
                    "filterType": "PRICE_FILTER",
                    "maxPrice": "300",
                    "minPrice": "0.0001", 
                    "tickSize": "0.0001"
                },
                {
                    "filterType": "LOT_SIZE", 
                    "maxQty": "10000000",
                    "minQty": "1",
                    "stepSize": "1"
                },
                {
                    "filterType": "MARKET_LOT_SIZE",
                    "maxQty": "590119",
                    "minQty": "1",
                    "stepSize": "1"
                },
                {
                    "filterType": "MAX_NUM_ORDERS",
                    "limit": 200
                },
                {
                    "filterType": "MAX_NUM_ALGO_ORDERS",
                    "limit": 100
                },
                {
                    "filterType": "MIN_NOTIONAL",
                    "notional": "1", 
                },
                {
                    "filterType": "PERCENT_PRICE",
                    "multiplierUp": "1.1500",
                    "multiplierDown": "0.8500",
                    "multiplierDecimal": 4
                }
            ],
            "OrderType": [
                "LIMIT",
                "MARKET",
                "STOP",
                "STOP_MARKET",
                "TAKE_PROFIT",
                "TAKE_PROFIT_MARKET",
                "TRAILING_STOP_MARKET" 
            ],
            "timeInForce": [
                "GTC", 
                "IOC", 
                "FOK", 
                "GTX" 
            ],
            "liquidationFee": "0.010000",   // liquidation fee rate
            "marketTakeBound": "0.30",  // the max price difference rate( from mark price) a market order can make
        }
    ],
    "timezone": "UTC" 
}

Насколько я понимаю, сейчас вся сложность в получении СкопированоstepSize по API. Написал небольшое консольное приложение / пример, которое получает список всех символов, СкопированоstepSize и печатает пример округления для указанного СкопированоworkAmount.

Код

using System.Text.Json;
using System.Text.Json.Serialization;

const string FORMAT = "{0,-15} {1,-8} {2, -8} {3, -20}";
const string PRICE_URL = "https://www.binance.com/fapi/v1/ticker/price";
const string EXCHANGE_INFO_URL = "https://www.binance.com/fapi/v1/exchangeInfo";

const decimal WORK_AMOUNT = 5;

Console.WriteLine(FORMAT, "Symbol", "Step", "Rounded", "Initial");

var exchangeModel = await Request<ExchangeModel>(EXCHANGE_INFO_URL);
var priceModels = await Request<IEnumerable<PriceModel>>(PRICE_URL);

foreach (var model in priceModels)
{
    var step = exchangeModel.Symbols
        .First(x => x.Symbol == model.Symbol).Filters
        .First(x => x.FilterType == "LOT_SIZE").StepSize;

    var initial = WORK_AMOUNT / model.Price;
    var rounded = Round(initial, step);

    Console.WriteLine(FORMAT, model.Symbol, step, rounded, initial);
}

static decimal Round(decimal number, decimal step)
{
    return Math.Floor(number / step) * step;
}

static async Task<T> Request<T>(string url)
{
    using var client = new HttpClient();
    var response = await client.GetAsync(url);
    response.EnsureSuccessStatusCode();

    var json = await response.Content.ReadAsStringAsync();
    return Deserialize<T>(json);
}

static T Deserialize<T>(string json)
{
    var options = new JsonSerializerOptions
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        NumberHandling = JsonNumberHandling.AllowReadingFromString
    };

    return JsonSerializer.Deserialize<T>(json, options)!;
}

record PriceModel(string Symbol, decimal Price);

record ExchangeModel(IEnumerable<SymbolModel> Symbols);
record SymbolModel(string Symbol, IEnumerable<FilterModel> Filters);
record FilterModel(string FilterType, decimal StepSize);

Пример вывода

Лайкнул Евгений
Евгений
Цитата: Dapofig от 25.01.2023, 22:02

Насколько я понимаю, сейчас вся сложность в получении СкопированоstepSize по API. Написал небольшое консольное приложение / пример, которое получает список всех символов, СкопированоstepSize и печатает пример округления для указанного СкопированоworkAmount.

Код

 
 
 
 
using System.Text.Json;
using System.Text.Json.Serialization;
 
const string FORMAT = "{0,-15} {1,-8} {2, -8} {3, -20}";
const string PRICE_URL = "https://www.binance.com/fapi/v1/ticker/price";
const string EXCHANGE_INFO_URL = "https://www.binance.com/fapi/v1/exchangeInfo";
 
const decimal WORK_AMOUNT = 5;
 
Console.WriteLine(FORMAT, "Symbol", "Step", "Rounded", "Initial");
 
var exchangeModel = await Request<ExchangeModel>(EXCHANGE_INFO_URL);
var priceModels = await Request<IEnumerable<PriceModel>>(PRICE_URL);
 
foreach (var model in priceModels)
{
var step = exchangeModel.Symbols
.First(x => x.Symbol == model.Symbol).Filters
.First(x => x.FilterType == "LOT_SIZE").StepSize;
 
var initial = WORK_AMOUNT / model.Price;
var rounded = Round(initial, step);
 
Console.WriteLine(FORMAT, model.Symbol, step, rounded, initial);
}
 
static decimal Round(decimal number, decimal step)
{
return Math.Floor(number / step) * step;
}
 
static async Task<T> Request<T>(string url)
{
using var client = new HttpClient();
var response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
 
var json = await response.Content.ReadAsStringAsync();
return Deserialize<T>(json);
}
 
static T Deserialize<T>(string json)
{
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
NumberHandling = JsonNumberHandling.AllowReadingFromString
};
 
return JsonSerializer.Deserialize<T>(json, options)!;
}
 
record PriceModel(string Symbol, decimal Price);
 
record ExchangeModel(IEnumerable<SymbolModel> Symbols);
record SymbolModel(string Symbol, IEnumerable<FilterModel> Filters);
record FilterModel(string FilterType, decimal StepSize);
using System.Text.Json; using System.Text.Json.Serialization; const string FORMAT = "{0,-15} {1,-8} {2, -8} {3, -20}"; const string PRICE_URL = "https://www.binance.com/fapi/v1/ticker/price"; const string EXCHANGE_INFO_URL = "https://www.binance.com/fapi/v1/exchangeInfo"; const decimal WORK_AMOUNT = 5; Console.WriteLine(FORMAT, "Symbol", "Step", "Rounded", "Initial"); var exchangeModel = await Request<ExchangeModel>(EXCHANGE_INFO_URL); var priceModels = await Request<IEnumerable<PriceModel>>(PRICE_URL); foreach (var model in priceModels) { var step = exchangeModel.Symbols .First(x => x.Symbol == model.Symbol).Filters .First(x => x.FilterType == "LOT_SIZE").StepSize; var initial = WORK_AMOUNT / model.Price; var rounded = Round(initial, step); Console.WriteLine(FORMAT, model.Symbol, step, rounded, initial); } static decimal Round(decimal number, decimal step) { return Math.Floor(number / step) * step; } static async Task<T> Request<T>(string url) { using var client = new HttpClient(); var response = await client.GetAsync(url); response.EnsureSuccessStatusCode(); var json = await response.Content.ReadAsStringAsync(); return Deserialize<T>(json); } static T Deserialize<T>(string json) { var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, NumberHandling = JsonNumberHandling.AllowReadingFromString }; return JsonSerializer.Deserialize<T>(json, options)!; } record PriceModel(string Symbol, decimal Price); record ExchangeModel(IEnumerable<SymbolModel> Symbols); record SymbolModel(string Symbol, IEnumerable<FilterModel> Filters); record FilterModel(string FilterType, decimal StepSize);
 
using System.Text.Json;
using System.Text.Json.Serialization;

const string FORMAT = "{0,-15} {1,-8} {2, -8} {3, -20}";
const string PRICE_URL = "https://www.binance.com/fapi/v1/ticker/price";
const string EXCHANGE_INFO_URL = "https://www.binance.com/fapi/v1/exchangeInfo";

const decimal WORK_AMOUNT = 5;

Console.WriteLine(FORMAT, "Symbol", "Step", "Rounded", "Initial");

var exchangeModel = await Request<ExchangeModel>(EXCHANGE_INFO_URL);
var priceModels = await Request<IEnumerable<PriceModel>>(PRICE_URL);

foreach (var model in priceModels)
{
    var step = exchangeModel.Symbols
        .First(x => x.Symbol == model.Symbol).Filters
        .First(x => x.FilterType == "LOT_SIZE").StepSize;

    var initial = WORK_AMOUNT / model.Price;
    var rounded = Round(initial, step);

    Console.WriteLine(FORMAT, model.Symbol, step, rounded, initial);
}

static decimal Round(decimal number, decimal step)
{
    return Math.Floor(number / step) * step;
}

static async Task<T> Request<T>(string url)
{
    using var client = new HttpClient();
    var response = await client.GetAsync(url);
    response.EnsureSuccessStatusCode();

    var json = await response.Content.ReadAsStringAsync();
    return Deserialize<T>(json);
}

static T Deserialize<T>(string json)
{
    var options = new JsonSerializerOptions
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        NumberHandling = JsonNumberHandling.AllowReadingFromString
    };

    return JsonSerializer.Deserialize<T>(json, options)!;
}

record PriceModel(string Symbol, decimal Price);

record ExchangeModel(IEnumerable<SymbolModel> Symbols);
record SymbolModel(string Symbol, IEnumerable<FilterModel> Filters);
record FilterModel(string FilterType, decimal StepSize);

Отлично! На выводе то, что нужно! Только вот я с этим кодом голову сломаю 😂 думал это как-то проще будет 😀

Страница 1 из 2►