207 lines
6.4 KiB
Dart
207 lines
6.4 KiB
Dart
import 'dart:math';
|
|
|
|
import 'package:intl/intl.dart';
|
|
import 'package:warp_api/data_fb_generated.dart' hide Quote;
|
|
import 'store.dart';
|
|
import 'package:warp_api/warp_api.dart';
|
|
import 'main.dart';
|
|
|
|
final DateFormat noteDateFormat = DateFormat("yy-MM-dd HH:mm");
|
|
final DateFormat txDateFormat = DateFormat("MM-dd HH:mm");
|
|
final DateFormat msgDateFormat = DateFormat("MM-dd HH:mm");
|
|
final DateFormat msgDateFormatFull = DateFormat("yy-MM-dd HH:mm:ss");
|
|
|
|
class DbReader {
|
|
int coin;
|
|
int id;
|
|
|
|
DbReader(int coin, int id): this.init(coin, id);
|
|
DbReader.init(this.coin, this.id);
|
|
|
|
List<Note> getNotes() {
|
|
final ns = WarpApi.getNotes(coin, id);
|
|
final notes = ns.map((n) {
|
|
final timestamp = DateTime.fromMillisecondsSinceEpoch(n.timestamp * 1000);
|
|
return Note(
|
|
n.id, n.height, timestamp, n.value / ZECUNIT, n.orchard, n.excluded, n.spent);
|
|
}).toList();
|
|
print("NOTES ${notes.length}");
|
|
return notes;
|
|
}
|
|
|
|
List<Tx> getTxs() {
|
|
final txs = WarpApi.getTxs(coin, id);
|
|
final transactions = txs.map((tx) {
|
|
final timestamp = DateTime.fromMillisecondsSinceEpoch(tx.timestamp * 1000);
|
|
return Tx(
|
|
tx.id,
|
|
tx.height,
|
|
timestamp,
|
|
tx.shortTxId!,
|
|
tx.txId!,
|
|
tx.value / ZECUNIT,
|
|
tx.address,
|
|
tx.name,
|
|
tx.memo);
|
|
}).toList();
|
|
print("TXS ${transactions.length}");
|
|
return transactions;
|
|
}
|
|
|
|
List<PnL> getPNL(int accountId) {
|
|
final range = _getChartRange();
|
|
|
|
final List<Trade> trades = [];
|
|
for (var row in WarpApi.getPnLTxs(coin, id, range.start ~/ 1000)) {
|
|
final dt = DateTime.fromMillisecondsSinceEpoch(row.timestamp * 1000);
|
|
final qty = row.value / ZECUNIT;
|
|
trades.add(Trade(dt, qty));
|
|
}
|
|
|
|
final portfolioTimeSeries = sampleDaily<Trade, Trade, double>(
|
|
trades,
|
|
range.start,
|
|
range.end,
|
|
(t) => t.dt.millisecondsSinceEpoch ~/ DAY_MS,
|
|
(t) => t,
|
|
(acc, t) => acc + t.qty,
|
|
0.0);
|
|
|
|
final List<Quote> quotes = [];
|
|
for (var row in WarpApi.getQuotes(coin, range.start ~/ 1000, settings.currency)) {
|
|
final dt = DateTime.fromMillisecondsSinceEpoch(row.timestamp * 1000);
|
|
final price = row.price;
|
|
quotes.add(Quote(dt, price));
|
|
}
|
|
|
|
var prevBalance = 0.0;
|
|
var cash = 0.0;
|
|
var realized = 0.0;
|
|
final List<PnL> pnls = [];
|
|
final len = min(quotes.length, portfolioTimeSeries.length);
|
|
for (var i = 0; i < len; i++) {
|
|
final dt = quotes[i].dt;
|
|
final price = quotes[i].price;
|
|
final balance = portfolioTimeSeries[i].value;
|
|
final qty = balance - prevBalance;
|
|
|
|
final closeQty = qty * balance < 0
|
|
? min(qty.abs(), prevBalance.abs()) * qty.sign
|
|
: 0.0;
|
|
final openQty = qty - closeQty;
|
|
final avgPrice = prevBalance != 0 ? cash / prevBalance : 0.0;
|
|
|
|
cash += openQty * price + closeQty * avgPrice;
|
|
realized += closeQty * (avgPrice - price);
|
|
final unrealized = price * balance - cash;
|
|
|
|
final pnl = PnL(dt, price, balance, realized, unrealized);
|
|
pnls.add(pnl);
|
|
|
|
prevBalance = balance;
|
|
}
|
|
return pnls;
|
|
}
|
|
|
|
List<Spending> getSpending(int accountId) {
|
|
final range = _getChartRange();
|
|
return WarpApi.getSpendings(coin, id, range.start ~/ 1000);
|
|
}
|
|
|
|
List<TimeSeriesPoint<double>> getAccountBalanceTimeSeries(int accountId, int balance) {
|
|
final range = _getChartRange();
|
|
final trades = WarpApi.getPnLTxs(coin, id, range.start ~/ 1000);
|
|
List<AccountBalance> _accountBalances = [];
|
|
var b = balance;
|
|
_accountBalances.add(AccountBalance(DateTime.now(), b / ZECUNIT));
|
|
for (var trade in trades) {
|
|
final timestamp =
|
|
DateTime.fromMillisecondsSinceEpoch(trade.timestamp * 1000);
|
|
final value = trade.value;
|
|
final ab = AccountBalance(timestamp, b / ZECUNIT);
|
|
_accountBalances.add(ab);
|
|
b -= value;
|
|
}
|
|
_accountBalances.add(AccountBalance(
|
|
DateTime.fromMillisecondsSinceEpoch(range.start), b / ZECUNIT));
|
|
_accountBalances = _accountBalances.reversed.toList();
|
|
final accountBalances = sampleDaily<AccountBalance, double, double>(
|
|
_accountBalances,
|
|
range.start,
|
|
range.end,
|
|
(AccountBalance ab) => ab.time.millisecondsSinceEpoch ~/ DAY_MS,
|
|
(AccountBalance ab) => ab.balance,
|
|
(acc, v) => v,
|
|
0.0);
|
|
return accountBalances;
|
|
}
|
|
|
|
List<ZMessage> getMessages() {
|
|
final messages = WarpApi.getMessages(coin, id);
|
|
return messages.map((m) =>
|
|
ZMessage(m.idMsg, m.idTx, m.incoming, m.from, m.to!, m.subject!, m.body!,
|
|
DateTime.fromMillisecondsSinceEpoch(m.timestamp * 1000), m.height, m.read)).toList();
|
|
}
|
|
|
|
// Future<List<TAccount>> getTAccounts() async {
|
|
// final List<Map> res = await db.rawQuery(
|
|
// "SELECT aindex, address, value FROM taddr_scan", []);
|
|
// List<TAccount> accounts = [];
|
|
// for (var row in res) {
|
|
// final aindex = row['aindex'];
|
|
// final address = row['address'];
|
|
// final balance = row['value'];
|
|
// final account = TAccount(aindex, address, balance);
|
|
// accounts.add(account);
|
|
// }
|
|
// db.execute("DELETE FROM taddr_scan");
|
|
// return accounts;
|
|
// }
|
|
|
|
TimeRange _getChartRange() {
|
|
final now = DateTime.now().toUtc();
|
|
final today = DateTime.utc(now.year, now.month, now.day);
|
|
final start = today.add(Duration(days: -_chartRangeDays()));
|
|
final cutoff = start.millisecondsSinceEpoch;
|
|
return TimeRange(cutoff, today.millisecondsSinceEpoch);
|
|
}
|
|
|
|
List<SendTemplateT> loadTemplates() {
|
|
final templates = WarpApi.getSendTemplates(coin);
|
|
return templates;
|
|
}
|
|
|
|
int _chartRangeDays() {
|
|
switch (settings.chartRange) {
|
|
case '1M':
|
|
return 30;
|
|
case '3M':
|
|
return 90;
|
|
case '6M':
|
|
return 180;
|
|
}
|
|
return 365;
|
|
}
|
|
}
|
|
|
|
class ZMessage {
|
|
final int id;
|
|
final int txId;
|
|
final bool incoming;
|
|
final String? sender;
|
|
final String recipient;
|
|
final String subject;
|
|
final String body;
|
|
final DateTime timestamp;
|
|
final int height;
|
|
final bool read;
|
|
|
|
ZMessage(this.id, this.txId, this.incoming, this.sender, this.recipient, this.subject, this.body, this.timestamp, this.height, this.read);
|
|
|
|
ZMessage withRead(bool v) {
|
|
return ZMessage(id, txId, incoming, sender, recipient, subject, body, timestamp, height, v);
|
|
}
|
|
|
|
String fromto() => incoming ? "\u{21e6} ${sender != null ? centerTrim(sender!) : ''}" : "\u{21e8} ${centerTrim(recipient)}";
|
|
}
|