Just My Life & My Work

[Flutter] HttpClient

現在手機主要功能就是拿來上網,所以任何 App 基本上都會需要透過網路存取資料,此時 Flutter 可以怎麼操作呢?使用內建 io package 就可搞定!🙃

我特地寫一個近年來很夯的比特幣查價系統,可以隨時查看多家交易平台上比特幣的實價,也許還可以進一步變成「搬磚」工具!

只要點擊藍色按鈕,就能即時取得多家交易所比特幣的實價。

剛好看到大神介紹開源項目,裡頭使用到 CryptoWatch 的開放 API,有些 API 就算不註冊也能使用,若註冊後會得到 API Key,便可無限量呼叫 API。目前我僅需要查詢交易所比特幣實價,先以這個簡單例子來實作。

/*
  Author: HappyMan
  Date: 2022/02/24
  Topic: HttpClient
 */
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List<String> marketPriceList = [];
  List<double> priceList = [];
  dynamic apiResponse;

  void callGetPriceAPI() {
    marketPriceList = [];
    priceList = [];
    // https://docs.cryptowat.ch/rest-api/
    _getPrice('https://api.cryptowat.ch/markets/coinbase-pro/btcusdt/price', 'Coinbase');
    _getPrice('https://api.cryptowat.ch/markets/binance/btcusdt/price', 'Binance');
    _getPrice('https://api.cryptowat.ch/markets/binance-us/btcusdt/price', 'Binance.US');
    _getPrice('https://api.cryptowat.ch/markets/huobi/btcusdt/price', 'Huobi');
    _getPrice('https://api.cryptowat.ch/markets/gateio/btcusdt/price', 'GateIO');
    _getPrice('https://api.cryptowat.ch/markets/okcoin/btcusdt/price', 'Okcoin');
    _getPrice('https://api.cryptowat.ch/markets/ftx/btcusdt/price', 'FTX');
    _getPrice('https://api.cryptowat.ch/markets/liquid/btcusdt/price', 'Liquid');
    _getPrice('https://api.cryptowat.ch/markets/okex/btcusdt/price', 'Okex');
    _getPrice('https://api.cryptowat.ch/markets/kraken/btcusdt/price', 'Kraken');
    _getPrice('https://api.cryptowat.ch/markets/cexio/btcusdt/price', 'CEX.IO');
    _getPrice('https://api.cryptowat.ch/markets/bitfinex/btcusdt/price', 'Bitfinex');
  }

  _getPrice(String url, String market) async {
    var httpClient = HttpClient();

    String result;
    try {
      var request = await httpClient.getUrl(Uri.parse(url));
      var response = await request.close();
      if (response.statusCode == HttpStatus.ok) {
        var json = await response.transform(utf8.decoder).join();
        var data = jsonDecode(json);
        result = market + ': ' + data['result']['price'].toString();
        apiResponse = data;
        print('apiResponse');
        print(apiResponse);
      } else {
        result = 'Error getting Bitcoin price:\nHttp status ${response.statusCode}';
      }
    } catch (exception) {
      result = 'Failed getting Bitcoin price';
      print('exception');
      print(exception);
    }

    setState(() {
      marketPriceList.add(result);

      // 解析取得價格
      var parts = result.split(' ');// Ex: "Binance: 37777.1"
      if (parts.length > 1) {
        priceList.add(double.parse(parts[1]));
      }
      print('priceList');
      print(priceList);
    });
  }

  @override
  Widget build(BuildContext context) {
    SizedBox spacer = SizedBox(height: 10.0);
    DateTime dateTime = DateTime.now();

    // 取得幣價最小值
    double _getMin(){
      if (priceList.length == 0)
        return 0;
      double min = priceList.first;
      for (int i = 1; i < priceList.length; i++) {
        if (min > priceList[i]) {
          min = priceList[i];
        }
      }
      return min;
    }
    // 取得幣價最大值
    double _getMax(){
      if (priceList.length == 0)
        return 0;
      double max = priceList.first;
      for (int i = 1; i < priceList.length; i++) {
        if (max < priceList[i]) {
          max = priceList[i];
        }
      }
      return max;
    }
    // 取得幣價最小值的市場
    String _getMinMarket(){
      double min = _getMin();
      for (int i = 1; i < marketPriceList.length; i++) {
        if (marketPriceList[i].contains(min.toString())) {
          // 解析取得市場
          var parts = marketPriceList[i].split(':');// Ex: "Binance: 37777.1"
          if (parts.length > 1) {
            return parts[0];
          }
        }
      }
      return 'None';
    }
    // 取得幣價最大值的市場
    String _getMaxMarket(){
      double max = _getMax();
      for (int i = 1; i < marketPriceList.length; i++) {
        if (marketPriceList[i].contains(max.toString())) {
          // 解析取得市場
          var parts = marketPriceList[i].split(':');// Ex: "Binance: 37777.1"
          if (parts.length > 1) {
            return parts[0];
          }
        }
      }
      return 'None';
    }

    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Your current Bitcoin price is:'),
            spacer,
            Container(
              decoration: BoxDecoration(
                borderRadius: BorderRadius.all(Radius.circular(30)),
                border: Border.all(
                  color: Colors.grey,
                  width: 3,
                ),
                color: Colors.black12,
              ),
              margin: EdgeInsets.all(50),
              height: 250,
              width: 200,
              child: Column(
                children: [
                  for (int i = 0; i < marketPriceList.length; i++)
                    Text(marketPriceList[i]),
                ],
              ),
            ),
            Text('Max: ' + _getMax().toString() + ' ' + _getMaxMarket(),
              style: TextStyle(
                color: Colors.redAccent,
              ),
            ),
            Text('Min: ' + _getMin().toString() + ' ' + _getMinMarket(),
              style: TextStyle(
                color: Colors.blueAccent,
              ),
            ),
            spacer,
            Text('Time: ' + dateTime.toString().substring(0,19)),
            spacer,
            ElevatedButton(
              onPressed: callGetPriceAPI,
              child: Text('Get Bitcoin price'),
            ),
            spacer,
            Container(
              margin: EdgeInsets.all(50),
              child: Text(
                apiResponse!=null?apiResponse.toString():'',
                style: TextStyle(
                  fontSize: 12,
                  color: Colors.black45,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

目前程式碼中我使用 12 家交易平台的數據,每次呼叫都會扣「零用錢」,若切換不同的 IP,則零用錢會再復原,現階段免費夠用就好~

以 Binance 為例:

https://api.cryptowat.ch/markets/binance/btcusdt/price

得到回傳:

// 20220224142639
// https://api.cryptowat.ch/markets/binance/btcusdt/price

{
  "result": {
    "price": 34859.04
  },
  "allowance": {
    "cost": 0.005,
    "remaining": 9.66,
    "upgrade": "For unlimited API access, create an account at https://cryptowat.ch"
  }
}

再查一下各平台買賣手續費 % 數(通常 0.05%-0.2%),一買一賣後扣掉手續費還能賺錢的話,就可以考慮用程式來「搬磚」囉~🤑

寫此專案的時刻,發生俄羅斯大戰烏克蘭事件,比特幣下跌至 35000 美金以下,好奇「買點」在哪裡呢?

有興趣的人,可以參考原始碼,然後請不吝給我星星,謝謝~🤠

https://github.com/happymanx/Exchange

參考:

隨意留個言吧:)~

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

標籤雲

%d 位部落客按了讚: