public static function getOnHold($for_update = false, $user_id = false, $user_fee = false) { global $CFG; if (!($user_id > 0)) { return false; } $user_fee = is_array($user_fee) ? $user_fee : FeeSchedule::getUserFees($user_id); $lock = $for_update ? 'LOCK IN SHARE MODE' : ''; $on_hold = array(); $sql = " SELECT currencies.currency AS currency, requests.amount AS amount FROM requests LEFT JOIN currencies ON (currencies.id = requests.currency) WHERE requests.site_user = "******" AND requests.request_type = {$CFG->request_widthdrawal_id} AND (requests.request_status = {$CFG->request_pending_id} OR requests.request_status = {$CFG->request_awaiting_id}) " . $lock; $result = db_query_array($sql); if ($result) { foreach ($result as $row) { if (!empty($on_hold[$row['currency']]['withdrawal'])) { $on_hold[$row['currency']]['withdrawal'] += floatval($row['amount']); } else { $on_hold[$row['currency']]['withdrawal'] = floatval($row['amount']); } if (!empty($on_hold[$row['currency']]['total'])) { $on_hold[$row['currency']]['total'] += floatval($row['amount']); } else { $on_hold[$row['currency']]['total'] = floatval($row['amount']); } } } $sql = " SELECT currencies.currency AS currency, orders.fiat AS amount, orders.btc AS btc_amount, orders.order_type AS type FROM orders LEFT JOIN currencies ON (currencies.id = orders.currency) WHERE orders.site_user = "******" " . $lock; $result = db_query_array($sql); if ($result) { foreach ($result as $row) { if ($row['type'] == $CFG->order_type_bid) { if (!empty($on_hold[$row['currency']]['order'])) { $on_hold[$row['currency']]['order'] += round(floatval($row['amount']) + floatval($row['amount']) * ($user_fee['fee'] * 0.01), 2, PHP_ROUND_HALF_UP); } else { $on_hold[$row['currency']]['order'] = round(floatval($row['amount']) + floatval($row['amount']) * ($user_fee['fee'] * 0.01), 2, PHP_ROUND_HALF_UP); } if (!empty($on_hold[$row['currency']]['total'])) { $on_hold[$row['currency']]['total'] += round(floatval($row['amount']) + floatval($row['amount']) * ($user_fee['fee'] * 0.01), 2, PHP_ROUND_HALF_UP); } else { $on_hold[$row['currency']]['total'] = round(floatval($row['amount']) + floatval($row['amount']) * ($user_fee['fee'] * 0.01), 2, PHP_ROUND_HALF_UP); } } else { if (!empty($on_hold['BTC']['order'])) { $on_hold['BTC']['order'] += floatval($row['btc_amount']); } else { $on_hold['BTC']['order'] = floatval($row['btc_amount']); } if (!empty($on_hold['BTC']['total'])) { $on_hold['BTC']['total'] += floatval($row['btc_amount']); } else { $on_hold['BTC']['total'] = floatval($row['btc_amount']); } } } } return $on_hold; }
public static function getOnHold($for_update = false, $user_id = false, $user_fee = false, $currencies = false) { global $CFG; if (!$CFG->session_active) { return false; } $user_id = $user_id > 0 ? $user_id : User::$info['id']; if ($CFG->memcached && !$currencies && empty($CFG->m_skip)) { $cached = $CFG->m->get('on_hold_' . $user_id); if (is_array($cached)) { self::$on_hold = $cached; if (!empty($cached)) { return $cached; } else { return false; } } } $user_fee = is_array($user_fee) ? $user_fee : FeeSchedule::getUserFees($user_id); $fee = $user_fee['fee1'] * 0.01; $lock = $for_update ? 'LOCK IN SHARE MODE' : ''; $on_hold = array(); if (!is_array($currencies) && $currencies > 0) { $currencies = array($currencies); } $currencies_str = ''; $currencies_str1 = ''; $amounts = array(); $amounts1 = array(); if (is_array($currencies)) { $currencies_str .= 'AND currency IN (' . implode(',', $currencies) . ')'; $currencies1 = $currencies; if (in_array($CFG->btc_currency_id, $currencies1)) { unset($currencies1[$CFG->btc_currency_id]); $currencies_str1 .= 'AND (order_type = ' . $CFG->order_type_ask . ' OR currency IN (' . implode(',', $currencies) . '))'; } else { $currencies_str1 .= 'AND currency IN (' . implode(',', $currencies1) . ')'; } foreach ($currencies as $currency_id) { $amounts[] = 'SUM(IF(currency = ' . $currency_id . ',amount,0)) AS ' . $CFG->currencies[$currency_id]['currency']; if ($currency_id != $CFG->btc_currency_id) { $amounts1[] = 'SUM(IF(order_type = ' . $CFG->order_type_bid . ' AND currency = ' . $currency_id . ',fiat + (fiat * ' . $fee . '),0)) AS ' . $CFG->currencies[$currency_id]['currency']; } else { $amounts1[] = 'SUM(IF(order_type = ' . $CFG->order_type_ask . ',btc,0)) AS ' . $CFG->currencies[$currency_id]['currency']; } } } else { foreach ($CFG->currencies as $currency_id => $currency1) { if (!is_numeric($currency_id)) { continue; } $amounts[] = 'SUM(IF(currency = ' . $currency_id . ',amount,0)) AS ' . $currency1['currency']; if ($currency_id != $CFG->btc_currency_id) { $amounts1[] = 'SUM(IF(order_type = ' . $CFG->order_type_bid . ' AND currency = ' . $currency_id . ',fiat + (fiat * ' . $fee . '),0)) AS ' . $currency1['currency']; } else { $amounts1[] = 'SUM(IF(order_type = ' . $CFG->order_type_ask . ',btc,0)) AS ' . $currency1['currency']; } } } $sql = "\n\t\tSELECT " . implode(',', $amounts) . ", 'r' AS type FROM requests WHERE site_user = {$user_id} AND request_type = {$CFG->request_widthdrawal_id} AND request_status IN ({$CFG->request_pending_id},{$CFG->request_awaiting_id}) {$currencies_str}\n\t\tUNION\n\t\tSELECT " . implode(',', $amounts1) . ", 'o' AS type FROM orders WHERE site_user = {$user_id} {$currencies_str1} {$lock}"; $result = db_query_array($sql); if ($result) { foreach ($result as $row) { foreach ($row as $field => $value) { if ($field == 'type') { continue; } if (!($value > 0) && !($currencies && in_array($CFG->currencies[$field]['id'], $currencies))) { continue; } if ($field != 'BTC') { $value = round($value, 2, PHP_ROUND_HALF_UP); } if ($row['type'] == 'r') { $on_hold[$field]['withdrawal'] = $value; } else { $on_hold[$field]['order'] = $value; } $on_hold[$field]['total'] = floatval($value) + (!empty($on_hold[$field]['total']) ? $on_hold[$field]['total'] : 0); } } } if (!$currencies && array_key_exists('BTC', $on_hold) && count($on_hold) > 1) { $btc_row = $on_hold['BTC']; unset($on_hold['BTC']); ksort($on_hold); $on_hold = array_merge(array('BTC' => $btc_row), $on_hold); } if ($CFG->memcached && !$currencies) { $on_hold1 = $on_hold ? $on_hold : array(); $CFG->m->set('on_hold_' . $user_id, $on_hold, 60); } self::$on_hold = $on_hold; return $on_hold; }
public static function executeOrder($buy, $price, $amount, $currency1, $fee, $market_price, $edit_id = 0, $this_user_id = 0, $external_transaction = false, $stop_price = false, $use_maker_fee = false, $verbose = false) { global $CFG; if (!$CFG->session_active) { return false; } if ($CFG->trading_status == 'suspended') { db_commit(); return array('error' => array('message' => Lang::string('buy-trading-disabled'), 'code' => 'TRADING_SUSPENDED')); } $this_user_id = preg_replace("/[^0-9]/", "", $this_user_id); $this_user_id = $this_user_id > 0 ? $this_user_id : User::$info['id']; if (!($this_user_id > 0)) { db_commit(); return array('error' => array('message' => 'Invalid authentication.', 'code' => 'AUTH_ERROR')); } $amount = preg_replace("/[^0-9\\.]/", "", $amount); $orig_amount = $amount; $price = preg_replace("/[^0-9\\.]/", "", $price); $stop_price = preg_replace("/[^0-9\\.]/", "", $stop_price); $currency1 = strtolower(preg_replace("/[^a-zA-Z]/", "", $currency1)); $edit_id = preg_replace("/[^0-9]/", "", $edit_id); db_start_transaction(); $orig_order = false; if ($edit_id > 0) { if (empty($CFG->session_api) || $external_transaction) { $orig_order = DB::getRecord('orders', $edit_id, 0, 1, false, false, false, 1); } else { $orig_order = self::getRecord(false, $edit_id, $this_user_id, true); } if ($orig_order['site_user'] != $this_user_id || !$orig_order) { db_commit(); return array('error' => array('message' => 'Order not found.', 'code' => 'ORDER_NOT_FOUND')); } $buy = $orig_order['order_type'] == $CFG->order_type_bid; $currency_info = $CFG->currencies[$orig_order['currency']]; $currency1 = strtolower($currency_info['currency']); $edit_id = $orig_order['id']; $use_maker_fee = $use_maker_fee && $orig_order['market_price'] != 'Y'; if ($external_transaction) { $amount = $orig_order['btc']; $orig_amount = $amount; } } else { $currency_info = $CFG->currencies[strtoupper($currency1)]; } $bid_ask = self::getBidAsk($currency1); $bid = $bid_ask['bid']; $ask = $bid_ask['ask']; $bid = $bid > $ask ? $ask : $bid; $price = $market_price ? $buy ? $ask : $bid : $price; $usd_info = $CFG->currencies['USD']; $user_balances = User::getBalances($this_user_id, array($currency_info['id'], $CFG->btc_currency_id), true); $user_fee = FeeSchedule::getUserFees($this_user_id); $on_hold = User::getOnHold(1, $this_user_id, $user_fee, array($currency_info['id'], $CFG->btc_currency_id)); $this_btc_balance = !empty($user_balances['btc']) ? $user_balances['btc'] : 0; $this_fiat_balance = !empty($user_balances[$currency1]) ? $user_balances[$currency1] : 0; $this_triggered_stop = $stop_price > 0 && $market_price; $stop_price = $stop_price > 0 && $market_price ? false : $stop_price; $fee = !$use_maker_fee ? $user_fee['fee'] : $user_fee['fee1']; $insert_id = 0; $transactions = 0; $new_order = 0; $edit_order = 0; $comp_btc_balance = array(); $comp_btc_on_hold = array(); $comp_fiat_balance = array(); $comp_fiat_on_hold = array(); $currency_max = false; $currency_max_str = false; $currency_min = false; $currency_min_str = false; $compatible = false; $trans_total = 0; $this_funds_finished = false; $hidden_executions = array(); $max_price = 0; $min_price = 0; $executed_orders = array(); $executed_prices = array(); $executed_orig_prices = false; $no_compatible = false; $triggered_rows = false; if (!empty($on_hold['BTC']['total'])) { $this_btc_on_hold = $edit_id > 0 && !$buy ? $on_hold['BTC']['total'] - $amount : $on_hold['BTC']['total']; } else { $this_btc_on_hold = 0; } if (!empty($on_hold[strtoupper($currency1)]['total'])) { $this_fiat_on_hold = $edit_id > 0 && $buy ? $on_hold[strtoupper($currency1)]['total'] - ($amount * $orig_order['btc_price'] + $amount * $orig_order['btc_price'] * ($fee * 0.01)) : $on_hold[strtoupper($currency1)]['total']; } else { $this_fiat_on_hold = 0; } $error = self::checkPreconditions($buy, $currency_info, $amount, $price, $stop_price, $fee, $buy ? $this_fiat_balance - $this_fiat_on_hold : $this_btc_balance - $this_btc_on_hold, $bid, $ask, $market_price, $this_user_id, $orig_order); if ($error) { db_commit(); return $error; } if (!$market_price) { $error = self::checkUserOrders($buy, $currency_info, $this_user_id, $price, $stop_price, $fee); if ($error) { db_commit(); return $error; } } if (!($edit_id > 0)) { $order_log_id = db_insert('order_log', array('date' => date('Y-m-d H:i:s'), 'order_type' => $buy ? $CFG->order_type_bid : $CFG->order_type_ask, 'site_user' => $this_user_id, 'btc' => $amount, 'fiat' => $amount * $price, 'currency' => $currency_info['id'], 'btc_price' => $price, 'market_price' => $market_price ? 'Y' : 'N', 'stop_price' => $stop_price, 'status' => 'ACTIVE')); } else { if (!$external_transaction || $this_triggered_stop) { $order_log_id = db_insert('order_log', array('date' => date('Y-m-d H:i:s'), 'order_type' => $buy ? $CFG->order_type_bid : $CFG->order_type_ask, 'site_user' => $this_user_id, 'btc' => $amount, 'fiat' => $amount * $price, 'currency' => $currency_info['id'], 'btc_price' => $price, 'market_price' => $market_price ? 'Y' : 'N', 'p_id' => $orig_order['log_id'], 'stop_price' => $stop_price, 'status' => 'ACTIVE')); db_update('order_log', $orig_order['log_id'], array('status' => 'REPLACED', 'btc_remaining' => $orig_order['btc'])); } else { $order_log_id = $orig_order['log_id']; } } if ($buy) { if ($price != $stop_price) { $compatible = self::getCompatible($CFG->order_type_ask, $price, $currency1, $amount, 1, $market_price, false, $use_maker_fee, $this_user_id); $no_compatible = !$compatible; $compatible = is_array($compatible) ? new ArrayIterator($compatible) : false; $compatible[] = array('continue' => 1); //$btc_commision = 0; $fiat_commision = false; $c = count($compatible); $i = 1; } if ($compatible) { foreach ($compatible as $comp_order) { if (!empty($comp_order['is_market']) && $comp_order['is_market'] == 'Y' && $price < $bid) { $hidden_executions[] = $comp_order; continue; } if (!empty($comp_order['real_market_price']) && round($comp_order['real_market_price'], 2, PHP_ROUND_HALF_UP) <= $price && round($comp_order['fiat_price'], 2, PHP_ROUND_HALF_UP) > $price && !$market_price) { $hidden_executions[] = $comp_order; continue; } if (!empty($comp_order['order_type']) && $comp_order['order_type'] == $CFG->order_type_bid) { if ($comp_order['is_market'] == 'Y') { $hidden_executions[] = $comp_order; } continue; } if (!($amount > 0) || !($this_fiat_balance - $this_fiat_on_hold > 0)) { $triggered = self::triggerStops($max_price, $min_price, $currency1, 1, $bid, $ask, $currency_max, $currency_min); $triggered_rows = self::getMarketOrders(); if ($triggered_rows) { $hidden_executions = array_merge($triggered_rows, $hidden_executions); } break; } elseif ($i == $c && $max_price > 0) { $triggered = self::triggerStops($max_price, $min_price, $currency1, 1, $bid, $ask, $currency_max, $currency_min); if ($triggered > 0) { $triggered_rows = self::getCompatible($CFG->order_type_ask, $max_price, $currency1, $amount, 1, $market_price, $executed_orders, false, false, true); if ($triggered_rows) { foreach ($triggered_rows as $triggered_row) { $compatible->append($triggered_row); } } } } if (!empty($comp_order['continue']) || $comp_order['site_user'] == $this_user_id) { $i++; continue; } $comp_user_info = self::lockOrder($comp_order['site_user'], $comp_order['id'], $comp_order['currency_id']); if (!$comp_user_info) { continue; } $comp_order = array_merge($comp_order, $comp_user_info); $comp_order['btc_balance'] = array_key_exists($comp_order['site_user'], $comp_btc_balance) ? $comp_btc_balance[$comp_order['site_user']] : $comp_order['btc_balance']; $comp_order['fiat_balance'] = array_key_exists($comp_order['site_user'], $comp_fiat_balance) ? $comp_fiat_balance[$comp_order['site_user']] : $comp_order['fiat_balance']; $comp_btc_on_hold[$comp_order['site_user']] = array_key_exists($comp_order['site_user'], $comp_btc_on_hold) ? $comp_btc_on_hold[$comp_order['site_user']] : $comp_order['btc_on_hold']; $max_amount = ($this_fiat_balance - $this_fiat_on_hold) / $comp_order['fiat_price'] > $amount + $fee * 0.01 * $amount ? $amount : ($this_fiat_balance - $this_fiat_on_hold) / $comp_order['fiat_price'] - $fee * 0.01 * (($this_fiat_balance - $this_fiat_on_hold) / $comp_order['fiat_price']); $max_comp_amount = $comp_order['btc_balance'] - ($comp_btc_on_hold[$comp_order['site_user']] - $comp_order['btc_outstanding']) > $comp_order['btc_outstanding'] ? $comp_order['btc_outstanding'] : $comp_order['btc_balance'] - ($comp_btc_on_hold[$comp_order['site_user']] - $comp_order['btc_outstanding']); $this_funds_finished = $max_amount < $amount; $comp_funds_finished = $max_comp_amount < $comp_order['btc_outstanding']; if (!($max_amount > 0) || !($max_comp_amount > 0)) { if ($comp_funds_finished) { self::cancelOrder($comp_order['id'], 0, $comp_order['site_user']); } $i++; continue; } if ($max_comp_amount >= $max_amount) { $trans_amount = $max_amount; $comp_order_outstanding = $comp_order['btc_outstanding'] - $max_amount; $amount = $amount - $max_amount; } else { $trans_amount = $max_comp_amount; $amount = $amount - $trans_amount; $comp_order_outstanding = $comp_order['btc_outstanding'] - $max_comp_amount; } $this_fee = $fee * 0.01 * $trans_amount; $comp_order_fee = $comp_order['fee1'] * 0.01 * $trans_amount; $this_conversion_fee = $currency_info['id'] != $comp_order['currency_id'] ? $comp_order['fiat_price'] * $trans_amount - $comp_order['orig_btc_price'] * $comp_order['orig_conversion_factor'] * $trans_amount : 0; $this_trans_amount_net = $trans_amount + $this_fee; $comp_order_trans_amount_net = $trans_amount - $comp_order_fee; $comp_btc_balance[$comp_order['site_user']] = $comp_order['btc_balance'] - $trans_amount; $comp_fiat_balance[$comp_order['site_user']] = round($comp_order['fiat_balance'] + $comp_order['orig_btc_price'] * $comp_order_trans_amount_net, 2, PHP_ROUND_HALF_UP); $comp_btc_on_hold[$comp_order['site_user']] = $comp_btc_on_hold[$comp_order['site_user']] - $trans_amount; //$btc_commision += $this_fee; if (!empty($fiat_commision[strtolower($currency_info['currency'])])) { $fiat_commision[strtolower($currency_info['currency'])] += $this_fee * $comp_order['fiat_price']; } else { $fiat_commision[strtolower($currency_info['currency'])] = $this_fee * $comp_order['fiat_price']; } if (!empty($fiat_commision[strtolower($comp_order['currency_abbr'])])) { $fiat_commision[strtolower($comp_order['currency_abbr'])] += $comp_order_fee * $comp_order['orig_btc_price']; } else { $fiat_commision[strtolower($comp_order['currency_abbr'])] = $comp_order_fee * $comp_order['orig_btc_price']; } $this_prev_btc = $this_btc_balance; $this_prev_fiat = $this_fiat_balance; $this_btc_balance += $trans_amount; $this_fiat_balance -= round($this_trans_amount_net * $comp_order['fiat_price'], 2, PHP_ROUND_HALF_UP); $trans_total += $trans_amount; $max_price = $comp_order['fiat_price'] > $max_price ? $comp_order['fiat_price'] : $max_price; $min_price = $comp_order['fiat_price'] < $min_price || !($min_price > 0) ? $comp_order['fiat_price'] : $min_price; if ($currency_info['id'] != $comp_order['currency_id']) { $currency_max[$comp_order['currency_id']] = $comp_order['orig_btc_price'] > $currency_max[$comp_order['currency_id']] ? $comp_order['orig_btc_price'] : $currency_max[$comp_order['currency_id']]; $currency_min[$comp_order['currency_id']] = $comp_order['orig_btc_price'] < $currency_min[$comp_order['currency_id']] || !($currency_min[$comp_order['currency_id']] > 0) ? $comp_order['orig_btc_price'] : $currency_min[$comp_order['currency_id']]; } $trans_info = array('date' => date('Y-m-d H:i:s'), 'site_user' => $this_user_id, 'transaction_type' => $CFG->transactions_buy_id, 'site_user1' => $comp_order['site_user'], 'transaction_type1' => $CFG->transactions_sell_id, 'btc' => $trans_amount, 'btc_price' => $comp_order['fiat_price'], 'fiat' => $comp_order['fiat_price'] * $trans_amount, 'currency' => $currency_info['id'], 'currency1' => $comp_order['currency_id'], 'fee' => $this_fee, 'fee1' => $comp_order_fee, 'btc_net' => $this_trans_amount_net, 'btc_net1' => $comp_order_trans_amount_net, 'btc_before' => $this_prev_btc, 'btc_after' => $this_btc_balance, 'fiat_before' => $this_prev_fiat, 'fiat_after' => $this_fiat_balance, 'btc_before1' => $comp_order['btc_balance'], 'btc_after1' => $comp_btc_balance[$comp_order['site_user']], 'fiat_before1' => $comp_order['fiat_balance'], 'fiat_after1' => $comp_fiat_balance[$comp_order['site_user']], 'log_id' => $order_log_id, 'log_id1' => $comp_order['log_id'], 'fee_level' => $fee, 'fee_level1' => $comp_order['fee'], 'conversion_fee' => $this_conversion_fee, 'orig_btc_price' => $comp_order['orig_btc_price'], 'bid_at_transaction' => $bid, 'ask_at_transaction' => $ask); if ($currency_info['id'] != $comp_order['currency_id']) { $trans_info = array_merge($trans_info, array('conversion' => 'Y', 'convert_amount' => $comp_order['fiat_price'] * $trans_amount, 'convert_rate_given' => $comp_order['conversion_factor'], 'convert_system_rate' => $comp_order['orig_conversion_factor'], 'convert_from_currency' => $currency_info['id'], 'convert_to_currency' => $comp_order['currency_id'])); } $transaction_id = db_insert('transactions', $trans_info); $executed_orders[] = $comp_order['id']; $executed_prices[] = array('price' => $comp_order['fiat_price'], 'amount' => $trans_amount); $executed_orig_prices[$comp_order['id']] = array('price' => $comp_order['orig_btc_price'], 'amount' => $trans_amount); ++$transactions; if (round($comp_order_outstanding, 8, PHP_ROUND_HALF_UP) > 0) { if (!$comp_funds_finished) { db_update('orders', $comp_order['id'], array('btc_price' => $comp_order['orig_btc_price'], 'btc' => $comp_order_outstanding, 'fiat' => $comp_order['orig_btc_price'] * $comp_order_outstanding)); if ($comp_order['is_market'] == 'Y') { $hidden_executions[] = $comp_order; } } else { self::cancelOrder($comp_order['id'], $comp_order_outstanding, $comp_order['site_user']); } } else { self::setStatus($comp_order['id'], 'FILLED'); db_delete('orders', $comp_order['id']); } User::updateBalances($comp_order['site_user'], array('btc' => $comp_btc_balance[$comp_order['site_user']], $comp_order['currency_abbr'] => $comp_fiat_balance[$comp_order['site_user']])); $i++; } } if ($trans_total > 0) { User::updateBalances($this_user_id, array('btc' => $this_btc_balance, $currency1 => $this_fiat_balance)); if ($fiat_commision) { Status::updateEscrows($fiat_commision); } //db_update('status',1,array('btc_escrow'=>($status['btc_escrow']+$btc_commision),strtolower($currency_info['currency']).'_escrow'=>($status[strtolower($currency_info['currency']).'_escrow']+$fiat_commision))); } if (round($amount, 8, PHP_ROUND_HALF_UP) > 0) { if ($edit_id > 0) { if (!$this_funds_finished) { if (!($no_compatible && $external_transaction)) { db_update('orders', $edit_id, array('btc' => $amount, 'fiat' => $amount * $price, 'currency' => $currency_info['id'], 'btc_price' => $price != $stop_price ? $price : 0, 'market_price' => $market_price ? 'Y' : 'N', 'log_id' => $order_log_id, 'stop_price' => $stop_price)); $edit_order = 1; } $order_status = 'ACTIVE'; } else { self::cancelOrder($edit_id, $amount, $this_user_id); $order_status = 'OUT_OF_FUNDS'; } } else { if (!$this_funds_finished) { db_insert('orders', array('date' => date('Y-m-d H:i:s'), 'order_type' => $CFG->order_type_bid, 'site_user' => $this_user_id, 'btc' => $amount, 'fiat' => $amount * $price, 'currency' => $currency_info['id'], 'btc_price' => $price != $stop_price ? $market_price && $max_price > 0 ? $max_price : $price : 0, 'market_price' => $market_price ? 'Y' : 'N', 'log_id' => $order_log_id, 'stop_price' => $stop_price)); $new_order = $stop_price != $price && $stop_price > 0 ? 2 : 1; $order_status = 'ACTIVE'; } else { self::cancelOrder(false, $amount, $this_user_id); $order_status = 'OUT_OF_FUNDS'; } } } elseif ($edit_id > 0) { self::setStatus($edit_id, 'FILLED'); db_delete('orders', $edit_id); $order_status = 'FILLED'; } else { self::setStatus(false, 'FILLED', $order_log_id); $order_status = 'FILLED'; } db_insert('history', array('date' => date('Y-m-d H:i:s'), 'ip' => !empty($CFG->client_ip) ? $CFG->client_ip : '', 'history_action' => $CFG->history_buy_id, 'site_user' => $this_user_id, 'order_id' => $order_log_id)); } else { if ($price != $stop_price) { $compatible = self::getCompatible($CFG->order_type_bid, $price, $currency1, $amount, 1, $market_price, false, $use_maker_fee, $this_user_id); $no_compatible = !$compatible; $compatible = is_array($compatible) ? new ArrayIterator($compatible) : false; $compatible[] = array('continue' => 1); //$btc_commision = 0; $fiat_commision = false; $c = count($compatible); $i = 1; } if ($compatible) { foreach ($compatible as $comp_order) { if (!empty($comp_order['is_market']) && $comp_order['is_market'] == 'Y' && $price > $ask) { $hidden_executions[] = $comp_order; continue; } if (!empty($comp_order['real_market_price']) && round($comp_order['real_market_price'], 2, PHP_ROUND_HALF_UP) >= $price && round($comp_order['fiat_price'], 2, PHP_ROUND_HALF_UP) < $price && !$market_price) { $hidden_executions[] = $comp_order; continue; } if (!empty($comp_order['order_type']) && $comp_order['order_type'] == $CFG->order_type_ask) { if ($comp_order['is_market'] == 'Y') { $hidden_executions[] = $comp_order; } continue; } if (!($amount > 0) || !($this_btc_balance - $this_btc_on_hold > 0)) { $triggered = self::triggerStops($max_price, $min_price, $currency1, false, $bid, $ask, $currency_max, $currency_min); $triggered_rows = self::getMarketOrders(); if ($triggered_rows) { $hidden_executions = array_merge($triggered_rows, $hidden_executions); } break; } elseif ($i == $c && $min_price > 0) { $triggered = self::triggerStops($max_price, $min_price, $currency1, false, $bid, $ask, $currency_max, $currency_min); if ($triggered > 0) { $triggered_rows = self::getCompatible($CFG->order_type_bid, $min_price, $currency1, $amount, 1, $market_price, $executed_orders, false, false, true); if ($triggered_rows) { foreach ($triggered_rows as $triggered_row) { $compatible->append($triggered_row); } } } } if (!empty($comp_order['continue']) || $comp_order['site_user'] == $this_user_id) { $i++; continue; } $comp_user_info = self::lockOrder($comp_order['site_user'], $comp_order['id'], $comp_order['currency_id']); if (!$comp_user_info) { continue; } $comp_order = array_merge($comp_order, $comp_user_info); $comp_order['btc_balance'] = array_key_exists($comp_order['site_user'], $comp_btc_balance) ? $comp_btc_balance[$comp_order['site_user']] : $comp_order['btc_balance']; $comp_order['fiat_balance'] = array_key_exists($comp_order['site_user'], $comp_fiat_balance) ? $comp_fiat_balance[$comp_order['site_user']] : $comp_order['fiat_balance']; $comp_fiat_on_hold[$comp_order['site_user']] = array_key_exists($comp_order['site_user'], $comp_fiat_on_hold) ? $comp_fiat_on_hold[$comp_order['site_user']] : round($comp_order['fiat_on_hold'], 2, PHP_ROUND_HALF_UP); $comp_fiat_this_on_hold = $comp_fiat_on_hold[$comp_order['site_user']] - ($comp_order['btc_outstanding'] * $comp_order['orig_btc_price'] + $comp_order['fee1'] * 0.01 * ($comp_order['btc_outstanding'] * $comp_order['orig_btc_price'])); $max_amount = $this_btc_balance - $this_btc_on_hold > $amount ? $amount : $this_btc_balance - $this_btc_on_hold; $max_comp_amount = ($comp_order['fiat_balance'] - $comp_fiat_this_on_hold) / $comp_order['orig_btc_price'] > $comp_order['btc_outstanding'] + $comp_order['fee1'] * 0.01 * $comp_order['btc_outstanding'] ? $comp_order['btc_outstanding'] : ($comp_order['fiat_balance'] - $comp_fiat_this_on_hold) / $comp_order['orig_btc_price'] - $comp_order['fee1'] * 0.01 * (($comp_order['fiat_balance'] - $comp_fiat_this_on_hold) / $comp_order['orig_btc_price']); $this_funds_finished = $max_amount < $amount; $comp_funds_finished = $max_comp_amount < $comp_order['btc_outstanding']; if (!($max_amount > 0) || !($max_comp_amount > 0)) { if ($comp_funds_finished) { self::cancelOrder($comp_order['id'], 0, $comp_order['site_user']); } $i++; continue; } if ($max_comp_amount >= $max_amount) { $trans_amount = $max_amount; $comp_order_outstanding = $comp_order['btc_outstanding'] - $amount; $amount = $amount - $max_amount; } else { $trans_amount = $max_comp_amount; $amount = $amount - $trans_amount; $comp_order_outstanding = $comp_order['btc_outstanding'] - $max_comp_amount; } $this_fee = $fee * 0.01 * $trans_amount; $comp_order_fee = $comp_order['fee1'] * 0.01 * $trans_amount; $this_trans_amount_net = $trans_amount - $this_fee; $this_conversion_fee = $currency_info['id'] != $comp_order['currency_id'] ? $comp_order['orig_btc_price'] * $comp_order['orig_conversion_factor'] * $trans_amount - $comp_order['fiat_price'] * $trans_amount : 0; $comp_order_trans_amount_net = $trans_amount + $comp_order_fee; $comp_btc_balance[$comp_order['site_user']] = $comp_order['btc_balance'] + $trans_amount; $comp_fiat_balance[$comp_order['site_user']] = $comp_order['fiat_balance'] - round($comp_order['orig_btc_price'] * $comp_order_trans_amount_net, 2, PHP_ROUND_HALF_UP); $comp_fiat_on_hold[$comp_order['site_user']] = $comp_fiat_on_hold[$comp_order['site_user']] - round($comp_order['orig_btc_price'] * $comp_order_trans_amount_net, 2, PHP_ROUND_HALF_UP); //$btc_commision += $comp_order_fee; if (!empty($fiat_commision[strtolower($currency_info['currency'])])) { $fiat_commision[strtolower($currency_info['currency'])] += $this_fee * $comp_order['fiat_price']; } else { $fiat_commision[strtolower($currency_info['currency'])] = $this_fee * $comp_order['fiat_price']; } if (!empty($fiat_commision[strtolower($comp_order['currency_abbr'])])) { $fiat_commision[strtolower($comp_order['currency_abbr'])] += $comp_order_fee * $comp_order['orig_btc_price']; } else { $fiat_commision[strtolower($comp_order['currency_abbr'])] = $comp_order_fee * $comp_order['orig_btc_price']; } $this_prev_btc = $this_btc_balance; $this_prev_fiat = $this_fiat_balance; $this_btc_balance -= $trans_amount; $this_fiat_balance += round($this_trans_amount_net * $comp_order['fiat_price'], 2, PHP_ROUND_HALF_UP); $trans_total += $trans_amount; $max_price = $comp_order['fiat_price'] > $max_price ? $comp_order['fiat_price'] : $max_price; $min_price = $comp_order['fiat_price'] < $min_price || !($min_price > 0) ? $comp_order['fiat_price'] : $min_price; if ($currency_info['id'] != $comp_order['currency_id']) { $currency_max[$comp_order['currency_id']] = $comp_order['orig_btc_price'] > $currency_max[$comp_order['currency_id']] ? $comp_order['orig_btc_price'] : $currency_max[$comp_order['currency_id']]; $currency_min[$comp_order['currency_id']] = $comp_order['orig_btc_price'] < $currency_min[$comp_order['currency_id']] || !($currency_min[$comp_order['currency_id']] > 0) ? $comp_order['orig_btc_price'] : $currency_min[$comp_order['currency_id']]; } $trans_info = array('date' => date('Y-m-d H:i:s'), 'site_user' => $this_user_id, 'transaction_type' => $CFG->transactions_sell_id, 'site_user1' => $comp_order['site_user'], 'transaction_type1' => $CFG->transactions_buy_id, 'btc' => $trans_amount, 'btc_price' => $comp_order['fiat_price'], 'fiat' => $comp_order['fiat_price'] * $trans_amount, 'currency' => $currency_info['id'], 'currency1' => $comp_order['currency_id'], 'fee' => $this_fee, 'fee1' => $comp_order_fee, 'btc_net' => $this_trans_amount_net, 'btc_net1' => $comp_order_trans_amount_net, 'btc_before' => $this_prev_btc, 'btc_after' => $this_btc_balance, 'fiat_before' => $this_prev_fiat, 'fiat_after' => $this_fiat_balance, 'btc_before1' => $comp_order['btc_balance'], 'btc_after1' => $comp_btc_balance[$comp_order['site_user']], 'fiat_before1' => $comp_order['fiat_balance'], 'fiat_after1' => $comp_fiat_balance[$comp_order['site_user']], 'log_id' => $order_log_id, 'log_id1' => $comp_order['log_id'], 'fee_level' => $fee, 'fee_level1' => $comp_order['fee'], 'conversion_fee' => $this_conversion_fee, 'orig_btc_price' => $comp_order['orig_btc_price'], 'bid_at_transaction' => $bid, 'ask_at_transaction' => $ask); if ($currency_info['id'] != $comp_order['currency_id']) { $trans_info = array_merge($trans_info, array('conversion' => 'Y', 'convert_amount' => $comp_order['orig_btc_price'] * $trans_amount, 'convert_rate_given' => $comp_order['conversion_factor'], 'convert_system_rate' => $comp_order['orig_conversion_factor'], 'convert_from_currency' => $comp_order['currency_id'], 'convert_to_currency' => $currency_info['id'])); } $transaction_id = db_insert('transactions', $trans_info); $executed_orders[] = $comp_order['id']; $executed_prices[] = array('price' => $comp_order['fiat_price'], 'amount' => $trans_amount); $executed_orig_prices[$comp_order['id']] = array('price' => $comp_order['orig_btc_price'], 'amount' => $trans_amount); ++$transactions; if ($currency_info['id'] != $comp_order['currency_id']) { db_update('transactions', $transaction_id, array('conversion' => 'Y', 'convert_amount' => $comp_order['orig_btc_price'] * $trans_amount, 'convert_rate_given' => $comp_order['conversion_factor'], 'convert_system_rate' => $comp_order['orig_conversion_factor'], 'convert_from_currency' => $comp_order['currency_id'], 'convert_to_currency' => $currency_info['id'])); } if (round($comp_order_outstanding, 8, PHP_ROUND_HALF_UP) > 0) { if (!$comp_funds_finished) { db_update('orders', $comp_order['id'], array('btc_price' => $comp_order['orig_btc_price'], 'btc' => $comp_order_outstanding, 'fiat' => $comp_order['orig_btc_price'] * $comp_order_outstanding)); if ($comp_order['is_market'] == 'Y') { $hidden_executions[] = $comp_order; } } else { self::cancelOrder($comp_order['id'], $comp_order_outstanding, $comp_order['site_user']); } } else { self::setStatus($comp_order['id'], 'FILLED'); db_delete('orders', $comp_order['id']); } User::updateBalances($comp_order['site_user'], array('btc' => $comp_btc_balance[$comp_order['site_user']], $comp_order['currency_abbr'] => $comp_fiat_balance[$comp_order['site_user']])); $i++; } } if ($trans_total > 0) { User::updateBalances($this_user_id, array('btc' => $this_btc_balance, $currency1 => $this_fiat_balance)); if ($fiat_commision) { Status::updateEscrows($fiat_commision); } } if (round($amount, 8, PHP_ROUND_HALF_UP) > 0) { if ($edit_id > 0) { if (!$this_funds_finished) { if (!($no_compatible && $external_transaction)) { db_update('orders', $edit_id, array('btc' => $amount, 'fiat' => $amount * $price, 'btc_price' => $price != $stop_price ? $price : 0, 'market_price' => $market_price ? 'Y' : 'N', 'log_id' => $order_log_id, 'stop_price' => $stop_price)); $edit_order = 1; } $order_status = 'ACTIVE'; } else { self::cancelOrder($edit_id, $amount, $this_user_id); $order_status = 'OUT_OF_FUNDS'; } } else { if (!$this_funds_finished) { $insert_id = db_insert('orders', array('date' => date('Y-m-d H:i:s'), 'order_type' => $CFG->order_type_ask, 'site_user' => $this_user_id, 'btc' => $amount, 'fiat' => $amount * $price, 'currency' => $currency_info['id'], 'btc_price' => $price != $stop_price ? $market_price && $min_price > 0 ? $min_price : $price : 0, 'market_price' => $market_price ? 'Y' : 'N', 'log_id' => $order_log_id, 'stop_price' => $stop_price)); $new_order = $stop_price != $price && $stop_price > 0 ? 2 : 1; $order_status = 'ACTIVE'; } else { self::cancelOrder(false, $amount, $this_user_id); $order_status = 'OUT_OF_FUNDS'; } } } elseif ($edit_id > 0) { self::setStatus($edit_id, 'FILLED'); db_delete('orders', $edit_id); $order_status = 'FILLED'; } else { self::setStatus(false, 'FILLED', $order_log_id); $order_status = 'FILLED'; } db_insert('history', array('date' => date('Y-m-d H:i:s'), 'ip' => !empty($CFG->client_ip) ? $CFG->client_ip : '', 'history_action' => $CFG->history_sell_id, 'site_user' => $this_user_id, 'order_id' => $order_log_id)); } db_commit(); if ($max_price > 0 && $currency1 == 'usd') { db_update('currencies', $CFG->btc_currency_id, array('usd_ask' => $max_price)); } if ($min_price > 0 && $currency1 == 'usd') { db_update('currencies', $CFG->btc_currency_id, array('usd_bid' => $min_price)); } if ($hidden_executions && !$external_transaction) { foreach ($hidden_executions as $comp_order) { if ($triggered_rows && $comp_order['is_market'] != 'Y') { continue; } $return = self::executeOrder($comp_order['order_type'] == $CFG->order_type_bid, $comp_order['orig_btc_price'], $comp_order['btc_outstanding'], strtolower($comp_order['currency_abbr']), false, $comp_order['is_market'] == 'Y', $comp_order['id'], $comp_order['site_user'], true, $comp_order['stop_price'], true, true); if (!empty($return['order_info']['comp_orig_prices'][$edit_id ? $edit_id : $insert_id])) { $executed_prices[] = $return['order_info']['comp_orig_prices'][$edit_id ? $edit_id : $insert_id]; ++$transactions; } } if ($verbose) { $reevaluated_order = DB::getRecord('orders', $edit_id ? $edit_id : $insert_id, 0, 1); if (!$reevaluated_order) { $order_status = 'FILLED'; } else { $amount = $reevaluated_order['btc']; } } } $order_info = false; if ($verbose) { if ($executed_prices) { foreach ($executed_prices as $exec) { $exec_amount[] = $exec['amount']; } $exec_amount_sum = array_sum($exec_amount); foreach ($executed_prices as $exec) { $avg_exec[] = $exec['amount'] / $exec_amount_sum * $exec['price']; } } $order_info = array('id' => $order_log_id, 'side' => $buy ? 'buy' : 'sell', 'type' => $market_price ? 'market' : ($stop_price > 0 ? 'stop' : 'limit'), 'amount' => $orig_amount, 'amount_remaining' => $amount, 'price' => round($price, 8, PHP_ROUND_HALF_UP), 'avg_price_executed' => count($executed_prices) > 0 ? round(array_sum($avg_exec), 2, PHP_ROUND_HALF_UP) : 0, 'stop_price' => $stop_price, 'currency' => strtoupper($currency1), 'status' => $order_status, 'replaced' => $edit_id ? $orig_order['log_id'] : 0, 'comp_orig_prices' => $executed_orig_prices); } return array('transactions' => $transactions, 'new_order' => $new_order, 'edit_order' => $edit_order, 'executed' => $executed_orders, 'order_info' => $order_info); }