Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added extra optional parameter "bid_amount_money" to "order.put_market_stock" RPC. #36

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions matchengine/me_load.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ static int load_limit_order(json_t *params)

static int load_market_order(json_t *params)
{
if (json_array_size(params) != 6)
if (json_array_size(params) != 6 && json_array_size(params) != 7)
return -__LINE__;

// user_id
Expand Down Expand Up @@ -313,7 +313,16 @@ static int load_market_order(json_t *params)
if (strlen(source) > SOURCE_MAX_LEN)
goto error;

int ret = market_put_market_order(false, NULL, market, user_id, side, amount, taker_fee, source);
// bid amount money (should the bid amount be treated as "money" or "stock")
// optional parameter, default is true
bool bid_amount_money = true;
if (json_array_size(params) == 7) {
if (!json_is_boolean(json_array_get(params, 6)))
goto error;
bid_amount_money = json_boolean_value(json_array_get(params, 6));
}

int ret = market_put_market_order(false, NULL, market, user_id, side, amount, taker_fee, source, bid_amount_money);

mpd_del(amount);
mpd_del(taker_fee);
Expand Down
147 changes: 110 additions & 37 deletions matchengine/me_market.c
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,7 @@ static int execute_market_ask_order(bool real, market_t *m, order_t *taker)
return 0;
}

static int execute_market_bid_order(bool real, market_t *m, order_t *taker)
static int execute_market_bid_order(bool real, market_t *m, order_t *taker, bool bid_amount_money)
{
mpd_t *price = mpd_new(&mpd_ctx);
mpd_t *amount = mpd_new(&mpd_ctx);
Expand All @@ -770,24 +770,32 @@ static int execute_market_bid_order(bool real, market_t *m, order_t *taker)
order_t *maker = node->value;
mpd_copy(price, maker->price, &mpd_ctx);

mpd_div(amount, taker->left, price, &mpd_ctx);
mpd_rescale(amount, amount, -m->stock_prec, &mpd_ctx);
while (true) {
mpd_mul(result, amount, price, &mpd_ctx);
if (mpd_cmp(result, taker->left, &mpd_ctx) > 0) {
mpd_set_i32(result, -m->stock_prec, &mpd_ctx);
mpd_pow(result, mpd_ten, result, &mpd_ctx);
mpd_sub(amount, amount, result, &mpd_ctx);
} else {
break;
if (bid_amount_money) {
mpd_div(amount, taker->left, price, &mpd_ctx);
mpd_rescale(amount, amount, -m->stock_prec, &mpd_ctx);
while (true) {
mpd_mul(result, amount, price, &mpd_ctx);
if (mpd_cmp(result, taker->left, &mpd_ctx) > 0) {
mpd_set_i32(result, -m->stock_prec, &mpd_ctx);
mpd_pow(result, mpd_ten, result, &mpd_ctx);
mpd_sub(amount, amount, result, &mpd_ctx);
} else {
break;
}
}
}

if (mpd_cmp(amount, maker->left, &mpd_ctx) > 0) {
mpd_copy(amount, maker->left, &mpd_ctx);
}
if (mpd_cmp(amount, mpd_zero, &mpd_ctx) == 0) {
break;
if (mpd_cmp(amount, maker->left, &mpd_ctx) > 0) {
mpd_copy(amount, maker->left, &mpd_ctx);
}
if (mpd_cmp(amount, mpd_zero, &mpd_ctx) == 0) {
break;
}
} else {
if (mpd_cmp(taker->left, maker->left, &mpd_ctx) < 0) {
mpd_copy(amount, taker->left, &mpd_ctx);
Copy link

@HumanSwissArmyKnifeQP HumanSwissArmyKnifeQP May 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(More of a stylistic and lower priority comment than anything else.)

For a file of this size, could we not replace many of the if/else blocks with a ternary operator, to improve code readability?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure but perhaps that kind of stylistic change should probably be in a dedicated PR

} else {
mpd_copy(amount, maker->left, &mpd_ctx);
}
}

mpd_mul(deal, price, amount, &mpd_ctx);
Expand All @@ -801,7 +809,11 @@ static int execute_market_bid_order(bool real, market_t *m, order_t *taker)
push_deal_message(taker->update_time, m->name, maker, taker, price, amount, ask_fee, bid_fee, MARKET_ORDER_SIDE_BID, deal_id, m->stock, m->money);
}

mpd_sub(taker->left, taker->left, deal, &mpd_ctx);
if (bid_amount_money) {
mpd_sub(taker->left, taker->left, deal, &mpd_ctx);
} else {
mpd_sub(taker->left, taker->left, amount, &mpd_ctx);
}
mpd_add(taker->deal_stock, taker->deal_stock, amount, &mpd_ctx);
mpd_add(taker->deal_money, taker->deal_money, deal, &mpd_ctx);
mpd_add(taker->deal_fee, taker->deal_fee, bid_fee, &mpd_ctx);
Expand Down Expand Up @@ -865,47 +877,108 @@ static int execute_market_bid_order(bool real, market_t *m, order_t *taker)
return 0;
}

int market_put_market_order(bool real, json_t **result, market_t *m, uint32_t user_id, uint32_t side, mpd_t *amount, mpd_t *taker_fee, const char *source)
int market_put_market_order(bool real, json_t **result, market_t *m, uint32_t user_id, uint32_t side, mpd_t *amount, mpd_t *taker_fee, const char *source, bool bid_amount_money)
{
if (side == MARKET_ORDER_SIDE_ASK) {
// validate user has the balance available to fulfil order
mpd_t *balance = balance_get(user_id, BALANCE_TYPE_AVAILABLE, m->stock);
if (!balance || mpd_cmp(balance, amount, &mpd_ctx) < 0) {
return -1;
}

// validate there are any market participants on the other side of the order
skiplist_iter *iter = skiplist_get_iterator(m->bids);
skiplist_node *node = skiplist_next(iter);
if (node == NULL) {
skiplist_release_iterator(iter);
return -3;
}
skiplist_release_iterator(iter);


// validate order amount is at least the minimum order amount
if (mpd_cmp(amount, m->min_amount, &mpd_ctx) < 0) {
return -2;
}
} else {
mpd_t *balance = balance_get(user_id, BALANCE_TYPE_AVAILABLE, m->money);
if (!balance || mpd_cmp(balance, amount, &mpd_ctx) < 0) {
return -1;
}
if (bid_amount_money) {
// validate user has the balance available to fulfil order
mpd_t *balance = balance_get(user_id, BALANCE_TYPE_AVAILABLE, m->money);
if (!balance || mpd_cmp(balance, amount, &mpd_ctx) < 0) {
return -1;
}

skiplist_iter *iter = skiplist_get_iterator(m->asks);
skiplist_node *node = skiplist_next(iter);
if (node == NULL) {
// validate there are any market participants on the other side of the order
skiplist_iter *iter = skiplist_get_iterator(m->asks);
skiplist_node *node = skiplist_next(iter);
if (node == NULL) {
skiplist_release_iterator(iter);
return -3;
}
skiplist_release_iterator(iter);
return -3;
}
skiplist_release_iterator(iter);

order_t *order = node->value;
mpd_t *require = mpd_new(&mpd_ctx);
mpd_mul(require, order->price, m->min_amount, &mpd_ctx);
if (mpd_cmp(amount, require, &mpd_ctx) < 0) {
// validate order amount is at least the minimum order amount
order_t *order = node->value;
mpd_t *require = mpd_new(&mpd_ctx);
mpd_mul(require, order->price, m->min_amount, &mpd_ctx);
if (mpd_cmp(amount, require, &mpd_ctx) < 0) {
mpd_del(require);
return -2;
}
mpd_del(require);
return -2;
} else {
// calculate money required and number of asks
mpd_t *money_required = mpd_new(&mpd_ctx);
mpd_t *left = mpd_new(&mpd_ctx);
mpd_t *amount_tx = mpd_new(&mpd_ctx);
mpd_t *price = mpd_new(&mpd_ctx);
mpd_t *deal = mpd_new(&mpd_ctx);
mpd_copy(money_required, mpd_zero, &mpd_ctx);
mpd_copy(left, amount, &mpd_ctx);
int ask_count = 0;
skiplist_node *node;
skiplist_iter *iter = skiplist_get_iterator(m->asks);
while ((node = skiplist_next(iter)) != NULL) {
ask_count++;
if (mpd_cmp(left, mpd_zero, &mpd_ctx) == 0) {
break;
}

order_t *maker = node->value;
mpd_copy(price, maker->price, &mpd_ctx);
if (mpd_cmp(maker->left, left, &mpd_ctx) < 0) {
mpd_copy(amount_tx, maker->left, &mpd_ctx);
} else {
mpd_copy(amount_tx, left, &mpd_ctx);
}

mpd_mul(deal, price, amount_tx, &mpd_ctx);
mpd_sub(left, left, amount_tx, &mpd_ctx);
mpd_add(money_required, money_required, deal, &mpd_ctx);
}
skiplist_release_iterator(iter);
mpd_del(left);
mpd_del(amount_tx);
mpd_del(price);
mpd_del(deal);

// validate user has the balance available to fulfil order
mpd_t *balance = balance_get(user_id, BALANCE_TYPE_AVAILABLE, m->money);
if (!balance || mpd_cmp(balance, money_required, &mpd_ctx) < 0) {
mpd_del(money_required);
return -1;
}
mpd_del(money_required);

// validate there are any market participants on the other side of the order
if (ask_count == 0) {
return -3;
}

// validate order amount is at least the minimum order amount
if (mpd_cmp(amount, m->min_amount, &mpd_ctx) < 0) {
return -2;
}
}
mpd_del(require);
}

order_t *order = malloc(sizeof(order_t));
Expand Down Expand Up @@ -945,7 +1018,7 @@ int market_put_market_order(bool real, json_t **result, market_t *m, uint32_t us
if (side == MARKET_ORDER_SIDE_ASK) {
ret = execute_market_ask_order(real, m, order);
} else {
ret = execute_market_bid_order(real, m, order);
ret = execute_market_bid_order(real, m, order, bid_amount_money);
}
if (ret < 0) {
log_error("execute order: %"PRIu64" fail: %d", order->id, ret);
Expand Down
2 changes: 1 addition & 1 deletion matchengine/me_market.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ market_t *market_create(struct market *conf);
int market_get_status(market_t *m, size_t *ask_count, mpd_t *ask_amount, size_t *bid_count, mpd_t *bid_amount);

int market_put_limit_order(bool real, json_t **result, market_t *m, uint32_t user_id, uint32_t side, mpd_t *amount, mpd_t *price, mpd_t *taker_fee, mpd_t *maker_fee, const char *source);
int market_put_market_order(bool real, json_t **result, market_t *m, uint32_t user_id, uint32_t side, mpd_t *amount, mpd_t *taker_fee, const char *source);
int market_put_market_order(bool real, json_t **result, market_t *m, uint32_t user_id, uint32_t side, mpd_t *amount, mpd_t *taker_fee, const char *source, bool bid_amount_money);
int market_cancel_order(bool real, json_t **result, market_t *m, order_t *order);

int market_put_order(market_t *m, order_t *order);
Expand Down
13 changes: 11 additions & 2 deletions matchengine/me_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ static int on_cmd_order_put_limit(nw_ses *ses, rpc_pkg *pkg, json_t *params)

static int on_cmd_order_put_market(nw_ses *ses, rpc_pkg *pkg, json_t *params)
{
if (json_array_size(params) != 6)
if (json_array_size(params) != 6 && json_array_size(params) != 7)
return reply_error_invalid_argument(ses, pkg);

// user_id
Expand Down Expand Up @@ -504,8 +504,17 @@ static int on_cmd_order_put_market(nw_ses *ses, rpc_pkg *pkg, json_t *params)
if (strlen(source) >= SOURCE_MAX_LEN)
goto invalid_argument;

// bid amount money (should the bid amount be treated as "money" or "stock")
// optional parameter, default is true
bool bid_amount_money = true;
if (json_array_size(params) == 7) {
if (!json_is_boolean(json_array_get(params, 6)))
goto invalid_argument;
bid_amount_money = json_boolean_value(json_array_get(params, 6));
}

json_t *result = NULL;
int ret = market_put_market_order(true, &result, market, user_id, side, amount, taker_fee, source);
int ret = market_put_market_order(true, &result, market, user_id, side, amount, taker_fee, source, bid_amount_money);

mpd_del(amount);
mpd_del(taker_fee);
Expand Down