You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

181 lines
5.2 KiB

/*
* Copyright (c) 2018, evilny0
*
* This file is part of cpfm.
*
* cpfm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* cpm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with cpfm. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "exchange.h"
#include "exchanges/kraken.h"
SQLPP_ALIAS_PROVIDER(bal);
ExchangesManager::ExchangesManager(int userId)
{
m_userId = userId;
}
ExchangesManager::~ExchangesManager()
{
}
void ExchangesManager::analyzeUserAccounts()
{
mysql::connection db(getMysqlConfig());
const auto exchanges_accounts = TableExchangesAccounts{};
// Identify coins, we need one analyzer object per exchange.
list<ExchangeHandler*> handlers;
for (const auto& row: db.run(select(exchanges_accounts.exchange_id,exchanges_accounts.account_id).from(exchanges_accounts).where(exchanges_accounts.user_id == m_userId)))
{
int exchangeId = row.exchange_id;
int accountId = row.account_id;
ExchangeHandler* handler;
switch (exchangeId)
{
case CPFM_EXCHANGE_ID_KRAKEN:
handler = new ExchangeHandlerKraken(m_userId,accountId);
handlers.push_back(handler);
break;
default:
lerr << "Unsupported exchange: " << exchangeId;
break;
}
}
for (auto const& handler: handlers)
{
handler->analyzeUserData();
delete handler;
}
}
ExchangeHandler::ExchangeHandler(int userId, int accountId)
{
m_userId = userId;
m_accountId = accountId;
}
ExchangeHandler::~ExchangeHandler()
{
}
void ExchangeHandler::getLedgersTotals()
{
mysql::connection db(getMysqlConfig());
const auto exchanges_ledgers = TableExchangesLedgers{};
const auto coins = TableCoins{};
map<int,Money> calcBalances;
map<int,Money> sqlCalcBalances;
map<int,Money> balances;
for (const auto& row: db.run(select(all_of(exchanges_ledgers)).from(exchanges_ledgers).unconditionally()))
{
Money amount(row.amount);
Money fee(row.fee);
Money x = calcBalances[row.coin_id];
Money prevBalance(x);
x = x + amount - fee;
calcBalances[row.coin_id] = x;
balances[row.coin_id] = x;
}
for (const auto& row: db.run(select(exchanges_ledgers.coin_id,sum(exchanges_ledgers.amount-exchanges_ledgers.fee).as(bal)).from(exchanges_ledgers).unconditionally().group_by(exchanges_ledgers.coin_id)))
{
Money x(row.bal);
sqlCalcBalances[row.coin_id] = x;
}
}
void ExchangeHandler::getTradesTotals()
{
mysql::connection db(getMysqlConfig());
const auto exchanges_trades = TableExchangesTrades{};
const auto coins = TableCoins{};
map<int,Money> medianBuyPrices;
map<int,Money> balances;
map<int,Money> earnings;
map<int,std::string> coinNames;
for (const auto& row: db.run(select(all_of(coins)).from(coins).unconditionally()))
{
coinNames[row.coin_id] = row.coin_short;
}
for (const auto& row: db.run(select(all_of(exchanges_trades)).from(exchanges_trades).unconditionally()))
{
Money price(row.price);
Money cost(row.cost);
Money fee(row.fee);
Money volume(row.volume);
int baseCoinId = row.base_coin_id;
int quoteCoinId = row.quote_coin_id;
int tradeType = row.type;
std::string sType;
Money prevMedianPrice(medianBuyPrices[baseCoinId]);
Money prevBalance(balances[baseCoinId]);
if (tradeType == CPFM_TRADE_TYPE_BUY)
{
sType = "buy";
medianBuyPrices[baseCoinId] = (medianBuyPrices[baseCoinId]*balances[baseCoinId] + price*volume) / (balances[baseCoinId]+volume);
balances[baseCoinId] += volume;
}
else if (tradeType == CPFM_TRADE_TYPE_SELL)
{
sType = "sale";
// median price does not change on sale, except if we reach balance 0. It should adjust correctly on next buy.
if (balances[baseCoinId] < volume)
{
lerr << "Trying to sell " << volume << " but balance is " << balances[baseCoinId];
}
else
{
balances[baseCoinId] -= volume;
earnings[baseCoinId] += (price-medianBuyPrices[baseCoinId])*volume;
}
}
}
}
void ExchangeHandler::emptyLedgers()
{
mysql::connection db(getMysqlConfig());
const auto exchanges_ledgers = TableExchangesLedgers{};
db.run(remove_from(exchanges_ledgers).unconditionally());
linfo << "Emptied Ledgers DB table";
}
void ExchangeHandler::emptyTrades()
{
mysql::connection db(getMysqlConfig());
const auto exchanges_trades = TableExchangesTrades{};
db.run(remove_from(exchanges_trades).unconditionally());
linfo << "Emptied Trades DB table";
}