761 lines
26 KiB
Ruby
761 lines
26 KiB
Ruby
# encoding: UTF-8
|
|
# frozen_string_literal: true
|
|
|
|
describe API::V2::Public::Markets, type: :request do
|
|
|
|
before(:each) { clear_redis }
|
|
describe 'GET /api/v2/markets' do
|
|
before { create(:market, :ethusd) }
|
|
|
|
let(:expected_keys) do
|
|
%w[id name base_unit quote_unit min_price max_price
|
|
min_amount amount_precision price_precision state]
|
|
end
|
|
|
|
it 'lists enabled markets' do
|
|
get '/api/v2/public/markets'
|
|
expect(response).to be_successful
|
|
result = JSON.parse(response.body)
|
|
|
|
expect(result.size).to eq Market.enabled.size
|
|
|
|
result.each do |market|
|
|
expect(market.keys).to contain_exactly(*expected_keys)
|
|
end
|
|
end
|
|
|
|
context 'api will return hidden markets' do
|
|
before { create(:market, :btceur, state: :hidden) }
|
|
it 'returns hidden market' do
|
|
get '/api/v2/public/markets'
|
|
expect(response).to be_successful
|
|
result = JSON.parse(response.body)
|
|
|
|
expect(result.find { |currency| currency['id'] == 'btceur' }['state']).to eq('hidden')
|
|
end
|
|
end
|
|
|
|
context 'pagination' do
|
|
it 'returns paginated markets' do
|
|
get '/api/v2/public/markets', params: { limit: 2 }
|
|
|
|
result = JSON.parse(response.body)
|
|
|
|
expect(response).to be_successful
|
|
|
|
expect(response.headers.fetch('Total').to_i).to eq Market.enabled.size
|
|
expect(result.size).to eq(2)
|
|
end
|
|
end
|
|
|
|
context 'filters' do
|
|
context 'base_unit & quote_unit' do
|
|
it 'filters by base_unit' do
|
|
get '/api/v2/public/markets', params: { base_unit: :btc }
|
|
expect(response).to be_successful
|
|
result = JSON.parse(response.body)
|
|
|
|
expect(result.size).to eq Market.enabled.where(base_unit: :btc).size
|
|
result.each do |market|
|
|
expect(market['base_unit']).to eq 'btc'
|
|
end
|
|
end
|
|
|
|
it 'filters by quote_unit' do
|
|
get '/api/v2/public/markets', params: { quote_unit: :usd }
|
|
expect(response).to be_successful
|
|
result = JSON.parse(response.body)
|
|
|
|
expect(result.size).to eq Market.enabled.where(quote_unit: :usd).size
|
|
result.each do |market|
|
|
expect(market['quote_unit']).to eq 'usd'
|
|
end
|
|
end
|
|
|
|
it 'does not filter' do
|
|
get '/api/v2/public/markets'
|
|
expect(response).to be_successful
|
|
result = JSON.parse(response.body)
|
|
|
|
expect(result.size).to eq Market.enabled.size
|
|
end
|
|
end
|
|
|
|
context 'base_code & quote_code' do
|
|
it 'filters by base_code' do
|
|
get '/api/v2/public/markets', params: { search: { base_code: "bt" } }
|
|
# Since we have next markets list:
|
|
# btcusd, btceth, ethusd
|
|
# Since 2 of them has 'bt' in base_unit (btc).
|
|
# We expect them to be returned in API response.
|
|
expect(response).to be_successful
|
|
result = JSON.parse(response.body)
|
|
|
|
expect(result.pluck('id')).to contain_exactly('btceth', 'btcusd')
|
|
end
|
|
|
|
it 'filters by quote_code' do
|
|
Currency.find(:eur).update(visible: true)
|
|
create(:market, :btceur)
|
|
# Since we have next markets list:
|
|
# btceur, btcusd, btceth, ethusd
|
|
# Since 2 of them has 'e' in quote_unit (eur, eth).
|
|
# We expect them to be returned in API response.
|
|
get '/api/v2/public/markets', params: { search: { quote_code: "e" } }
|
|
expect(response).to be_successful
|
|
result = JSON.parse(response.body)
|
|
|
|
expect(result.pluck('id')).to contain_exactly('btceth', 'btceur')
|
|
end
|
|
end
|
|
|
|
context 'quote_name' do
|
|
before do
|
|
Currency.find(:eur).update(visible: true)
|
|
create(:market, :btceur)
|
|
create(:market, :btctrst)
|
|
end
|
|
|
|
it 'filters by name 1' do
|
|
# Since we have next markets list:
|
|
# btceur, btcusd, btceth, btctrst, ethusd
|
|
# Since 3 of them has 'E' in quote name (Euro, Ethereum, We Trust).
|
|
# We expect them to be returned in API response.
|
|
get '/api/v2/public/markets', params: { search: { quote_name: 'E' } }
|
|
expect(response).to be_successful
|
|
result = JSON.parse(response.body)
|
|
expect(result.pluck('id')).to contain_exactly('btceth', 'btceur', 'btctrst')
|
|
end
|
|
|
|
it 'filters by name 2' do
|
|
# Since we have next markets list:
|
|
# btceur, btcusd, btceth, btctrst, ethusd
|
|
# Since 3 of them has 'uS' in quote name (US Dollar, We Trust).
|
|
# We expect them to be returned in API response.
|
|
get '/api/v2/public/markets', params: { search: { quote_name: 'uS' } }
|
|
expect(response).to be_successful
|
|
result = JSON.parse(response.body)
|
|
expect(result.pluck('id')).to contain_exactly('btcusd', 'btctrst', 'ethusd')
|
|
end
|
|
end
|
|
|
|
context 'complex filter' do
|
|
before do
|
|
Currency.find(:eur).update(visible: true)
|
|
create(:market, :btceur)
|
|
create(:market, :btctrst)
|
|
end
|
|
|
|
it 'filters by base_unit & quote_name or quote_code' do
|
|
# Since we have next markets list:
|
|
# btceur, btcusd, btceth, btctrst, ethusd
|
|
# 1. Filter by base_unit btc: btceur, btcusd, btceth, btctrst
|
|
# 2. Filter by quote_code or quote_name 'et': btceth, btctrst (Ethereum, WeTrust)
|
|
# We expect them to be returned in API response.
|
|
get '/api/v2/public/markets', params: { base_unit: :btc, search: { quote_name: 'et', quote_code: 'et' } }
|
|
expect(response).to be_successful
|
|
result = JSON.parse(response.body)
|
|
expect(result.pluck('id')).to contain_exactly('btceth', 'btctrst')
|
|
end
|
|
|
|
it 'filters by base_unit & quote_code' do
|
|
# Since we have next markets list:
|
|
# btceur, btcusd, btceth, btctrst, ethusd
|
|
# 1. Filter by base_unit btc: btceur, btcusd, btceth, btctrst
|
|
# 2. Filter by quote_code 'et': btceth (eth)
|
|
# We expect them to be returned in API response.
|
|
get '/api/v2/public/markets', params: { base_unit: :btc, search: { quote_code: 'et' } }
|
|
expect(response).to be_successful
|
|
result = JSON.parse(response.body)
|
|
expect(result.pluck('id')).to contain_exactly('btceth')
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'GET /api/v2/public/markets/:market/order_book' do
|
|
before do
|
|
create_list(:order_bid, 5, :btcusd)
|
|
create_list(:order_ask, 5, :btcusd)
|
|
end
|
|
|
|
let(:market) { :btcusd }
|
|
|
|
it 'returns ask and bid orders on specified market' do
|
|
get "/api/v2/public/markets/#{market}/order-book"
|
|
expect(response).to be_successful
|
|
|
|
result = JSON.parse(response.body)
|
|
expect(result['asks'].size).to eq 5
|
|
expect(result['bids'].size).to eq 5
|
|
end
|
|
|
|
context 'market name with dot' do
|
|
let!(:currency) { create(:currency, :xagm_cx) }
|
|
let!(:market) { create(:market, :xagm_cxusd) }
|
|
|
|
it 'returns information about specified market' do
|
|
get "/api/v2/public/markets/#{market.id}/order-book"
|
|
expect(response).to be_successful
|
|
|
|
result = JSON.parse(response.body)
|
|
expect(result['asks'].size).to eq 0
|
|
expect(result['bids'].size).to eq 0
|
|
end
|
|
end
|
|
|
|
it 'returns limited asks and bids' do
|
|
get "/api/v2/public/markets/#{market}/order-book", params: { asks_limit: 1, bids_limit: 1 }
|
|
expect(response).to be_successful
|
|
|
|
result = JSON.parse(response.body)
|
|
expect(result['asks'].size).to eq 1
|
|
expect(result['bids'].size).to eq 1
|
|
end
|
|
|
|
it 'validates market param' do
|
|
get "/api/v2/public/markets/somecoin/order-book", params: { asks_limit: 1, bids_limit: 1 }
|
|
expect(response).to have_http_status 422
|
|
expect(response).to include_api_error('public.market.doesnt_exist')
|
|
end
|
|
|
|
it 'validates asks limit' do
|
|
get "/api/v2/public/markets/somecoin/order-book", params: { asks_limit: 201, bids_limit: 1 }
|
|
expect(response).to have_http_status 422
|
|
expect(response).to include_api_error('public.order_book.invalid_ask_limit')
|
|
end
|
|
|
|
it 'validates bids limit' do
|
|
get "/api/v2/public/markets/somecoin/order-book", params: { asks_limit: 1, bids_limit: 201 }
|
|
expect(response).to have_http_status 422
|
|
expect(response).to include_api_error('public.order_book.invalid_bid_limit')
|
|
end
|
|
end
|
|
|
|
describe 'GET /api/v2/markets/:market/depth' do
|
|
before do
|
|
create_list(:order_bid, 5, :btcusd)
|
|
create_list(:order_bid, 5, :btcusd, price: 2)
|
|
create_list(:order_ask, 5, :btcusd)
|
|
create_list(:order_ask, 5, :btcusd, price: 3)
|
|
end
|
|
|
|
let(:asks) { [["1.0", "5.0"], ["3.0", "5.0"]] }
|
|
let(:bids) { [["2.0", "5.0"], ["1.0", "5.0"]] }
|
|
|
|
let(:market) { :btcusd }
|
|
|
|
context 'valid market param' do
|
|
it 'sorts asks and bids from highest to lowest' do
|
|
get "/api/v2/public/markets/#{market}/depth"
|
|
expect(response).to be_successful
|
|
|
|
result = JSON.parse(response.body)
|
|
expect(result['asks']).to eq asks
|
|
expect(result['bids']).to eq bids
|
|
end
|
|
end
|
|
|
|
context 'market name with dot' do
|
|
let!(:currency) { create(:currency, :xagm_cx) }
|
|
let!(:market) { create(:market, :xagm_cxusd) }
|
|
|
|
it 'returns information about specified market' do
|
|
get "/api/v2/public/markets/#{market.id}/depth"
|
|
expect(response).to be_successful
|
|
|
|
result = JSON.parse(response.body)
|
|
expect(result['asks'].size).to eq 0
|
|
expect(result['bids'].size).to eq 0
|
|
end
|
|
end
|
|
|
|
context 'invalid market param' do
|
|
it 'validates market param' do
|
|
api_get "/api/v2/public/markets/usdusd/depth"
|
|
expect(response).to have_http_status 422
|
|
expect(response).to include_api_error('public.market.doesnt_exist')
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'GET /api/v2/public/markets/market/k-line' do
|
|
let(:points) do
|
|
# [timestamp, open_price, max_price, min_price, last_price, period_volume]
|
|
[[1537370460, 0.7079, 0.2204, 0.9794, 0.5273, 0.0747],
|
|
[1537370520, 0.6293, 0.5054, 0.2253, 0.1969, 0.7276],
|
|
[1537370580, 0.0939, 0.1949, 0.0032, 0.8328, 0.5895],
|
|
[1537370640, 0.6416, 0.0772, 0.7045, 0.7794, 0.6151],
|
|
[1537370700, 0.0566, 0.6377, 0.3007, 0.6855, 0.6976],
|
|
[1537370760, 0.7868, 0.6465, 0.3207, 0.6428, 0.1771],
|
|
[1537370820, 0.3318, 0.2124, 0.3773, 0.4274, 0.3473],
|
|
[1537370880, 0.0704, 0.4902, 0.5957, 0.5214, 0.3687],
|
|
[1537370940, 0.6629, 0.6585, 0.0756, 0.4559, 0.8554],
|
|
[1537371000, 0.6627, 0.6627, 0.2128, 0.0788, 0.2013],
|
|
[1537371060, 0.5165, 0.0435, 0.5228, 0.6447, 0.9237],
|
|
[1537371120, 0.9311, 0.8886, 0.1605, 0.3223, 0.0211],
|
|
[1537371180, 0.0704, 0.0103, 0.0325, 0.3846, 0.8957],
|
|
[1537371240, 0.1445, 0.6031, 0.9533, 0.0866, 0.4871],
|
|
[1537371300, 0.0974, 0.1344, 0.1533, 0.9029, 0.2009],
|
|
[1537371360, 0.2609, 0.9687, 0.0287, 0.4465, 0.7088],
|
|
[1537371420, 0.5671, 0.0576, 0.6617, 0.1041, 0.4942],
|
|
[1537371480, 0.8355, 0.5336, 0.7419, 0.7062, 0.9562],
|
|
[1537371540, 0.1805, 0.3577, 0.2768, 0.3162, 0.0209],
|
|
[1537371600, 0.7971, 0.1799, 0.8307, 0.5074, 0.0122],
|
|
[1537371660, 0.9491, 0.7448, 0.2019, 0.4662, 0.7035],
|
|
[1537371720, 0.8126, 0.3899, 0.8823, 0.8115, 0.6067],
|
|
[1537371780, 0.2632, 0.6558, 0.7411, 0.3894, 0.1509],
|
|
[1537371840, 0.4274, 0.8187, 0.6661, 0.4331, 0.6335],
|
|
[1537371900, 0.1356, 0.1787, 0.3081, 0.9549, 0.0723],
|
|
[1537371960, 0.1931, 0.9486, 0.2469, 0.2295, 0.9366],
|
|
[1537372020, 0.8323, 0.8168, 0.8453, 0.1278, 0.7975],
|
|
[1537372080, 0.5663, 0.1374, 0.0025, 0.0358, 0.6063],
|
|
[1537372140, 0.9296, 0.5443, 0.2732, 0.6434, 0.9173],
|
|
[1537372200, 0.7292, 0.0367, 0.3569, 0.7876, 0.6626],
|
|
[1537372260, 0.9979, 0.2182, 0.5141, 0.8984, 0.4512],
|
|
[1537372320, 0.4363, 0.4416, 0.2354, 0.6053, 0.7398],
|
|
[1537372380, 0.1815, 0.4969, 0.4091, 0.0798, 0.8797]]
|
|
end
|
|
let(:point_period) { KLineService::POINT_PERIOD_IN_SECONDS }
|
|
let(:points_default_limit) { 30 }
|
|
let(:last_point) { points.last }
|
|
let(:first_point) { points.first }
|
|
|
|
before { write_to_influx(points) }
|
|
after { delete_measurments("candles_1m") }
|
|
|
|
def influx_data(point)
|
|
{
|
|
values:
|
|
{
|
|
open: point[1],
|
|
high: point[2],
|
|
low: point[3],
|
|
close: point[4],
|
|
volume: point[5],
|
|
},
|
|
tags:
|
|
{
|
|
market: 'btcusd'
|
|
},
|
|
timestamp: point[0]
|
|
}
|
|
end
|
|
|
|
def write_to_influx(points)
|
|
points.each do |point|
|
|
Peatio::InfluxDB.client(epoch: 's').write_point('candles_1m', influx_data(point), 's')
|
|
end
|
|
end
|
|
|
|
def load_k_line(query = {})
|
|
api_get '/api/v2/public/markets/btcusd/k-line?' + query.to_query
|
|
expect(response).to have_http_status 200
|
|
end
|
|
|
|
def response_body
|
|
JSON.parse(response.body)
|
|
end
|
|
|
|
context 'data exists' do
|
|
it 'without time limits' do
|
|
load_k_line
|
|
expect(JSON.parse(response.body)).to eq points[-points_default_limit..-1]
|
|
end
|
|
|
|
context 'with time_from' do
|
|
it 'smaller than first point timestamp' do
|
|
load_k_line(time_from: first_point.first - 2 * point_period)
|
|
expect(response_body).to eq points[0...points_default_limit]
|
|
end
|
|
|
|
it 'bigger than last point timestamp' do
|
|
load_k_line(time_from: last_point.first + 2 * point_period)
|
|
expect(response_body).to eq []
|
|
end
|
|
|
|
it 'in range of first and last timestamp' do
|
|
time_from = first_point.first + 10 * point_period
|
|
load_k_line(time_from: time_from)
|
|
expect(response_body).to eq points[10..-1]
|
|
# First point timestamp should be eq to time_from.
|
|
expect(response_body.first.first).to eq time_from
|
|
|
|
time_from = first_point.first + 22 * point_period
|
|
load_k_line(time_from: time_from)
|
|
expect(response_body).to eq points[22..-1]
|
|
# First point timestamp should be eq to time_from.
|
|
expect(response_body.first.first).to eq time_from
|
|
end
|
|
end
|
|
|
|
context 'with time_to' do
|
|
it 'smaller than first point timestamp' do
|
|
load_k_line(time_to: first_point.first - 2 * point_period)
|
|
expect(response_body).to eq []
|
|
end
|
|
|
|
it 'bigger than last point timestamp' do
|
|
load_k_line(time_to: last_point.first + 2 * point_period)
|
|
# Returns (limit - 2) left points.
|
|
expect(response_body).to eq points[-points_default_limit..]
|
|
end
|
|
|
|
it 'in range of first and last timestamp' do
|
|
load_k_line(time_to: first_point.first + 1 * point_period)
|
|
expect(response_body).to eq points[0..1]
|
|
|
|
load_k_line(time_to: first_point.first + 20 * point_period)
|
|
expect(response_body).to eq points[0..20]
|
|
end
|
|
end
|
|
|
|
context 'with time_from and time_to' do
|
|
|
|
it 'time_to less than time_from' do
|
|
time_from = first_point.first + 2 * point_period
|
|
time_to = first_point.first - 2 * point_period
|
|
|
|
load_k_line(time_from: time_from, time_to: time_to)
|
|
expect(response_body).to eq []
|
|
end
|
|
|
|
it 'both less than first point timestamp' do
|
|
time_from = first_point.first - 10 * point_period
|
|
time_to = first_point.first - 4 * point_period
|
|
|
|
load_k_line(time_from: time_from, time_to: time_to)
|
|
expect(response_body).to eq []
|
|
end
|
|
|
|
it 'both bigger than last point timestamp' do
|
|
time_from = last_point.first + 2 * point_period
|
|
time_to = last_point.first + 12 * point_period
|
|
|
|
load_k_line(time_from: time_from, time_to: time_to)
|
|
expect(response_body).to eq []
|
|
end
|
|
|
|
it 'both in range of first and last timestamp' do
|
|
time_from = first_point.first + 10 * point_period
|
|
time_to = last_point.first - 10 * point_period
|
|
|
|
load_k_line(time_from: time_from, time_to: time_to)
|
|
# Points timestamps should be in range time_from..time_to (limit is bigger).
|
|
expect(response_body).to eq\
|
|
points.select { |p| p.first >= time_from && p.first <= time_to }
|
|
expect(response_body.first.first).to eq time_from
|
|
expect(response_body.last.first).to eq time_to
|
|
end
|
|
end
|
|
|
|
context 'with limit' do
|
|
it 'returns n last points' do
|
|
limit = 5
|
|
load_k_line(limit: limit)
|
|
expect(response_body).to eq points[-limit..-1]
|
|
|
|
limit = 10
|
|
load_k_line(limit: limit)
|
|
expect(response_body).to eq points[-limit..-1]
|
|
end
|
|
|
|
it 'returns all points if limit greater than points number' do
|
|
limit = points.length + 1
|
|
load_k_line(limit: limit)
|
|
expect(response_body).to eq points
|
|
end
|
|
end
|
|
|
|
context 'with limits, time_from and time_to' do
|
|
it 'ignores limit' do
|
|
time_from = first_point.first + 1 * point_period
|
|
time_to = last_point.first - 1 * point_period
|
|
limit = 5
|
|
load_k_line(time_from: time_from, time_to: time_to, limit: limit)
|
|
|
|
# All point in time_from..time_to including time_to (time_to - time_from) / 60 + 1.
|
|
expect(response_body.count).to eq (time_to - time_from) / 60 + 1
|
|
# Points timestamps should be in range time_from..time_to.
|
|
expect(response_body).to eq\
|
|
points.select { |p| p.first >= time_from && p.first <= time_to }
|
|
expect(response_body.first.first).to eq time_from
|
|
expect(response_body.last.first).to eq time_to
|
|
end
|
|
end
|
|
|
|
context 'with limits and time_from' do
|
|
it 'returns n right points from time_from (adds limit to time_from)' do
|
|
time_from = first_point.first + 5 * point_period
|
|
limit = 10
|
|
load_k_line(time_from: time_from, limit: limit)
|
|
|
|
expect(response_body.count).to eq limit
|
|
# Points timestamps should be bigger than time_from and we select first 10.
|
|
expect(response_body).to eq\
|
|
points.select { |p| p.first >= time_from }[0...limit]
|
|
expect(response_body.first.first).to eq time_from
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'data is missing' do
|
|
before { delete_measurments("candles_1m") }
|
|
|
|
it 'without time_from' do
|
|
load_k_line
|
|
expect(JSON.parse(response.body)).to eq []
|
|
end
|
|
|
|
it 'with time_from' do
|
|
load_k_line(time_from: first_point.first)
|
|
expect(JSON.parse(response.body)).to eq []
|
|
end
|
|
|
|
it 'with time_from and time_to' do
|
|
load_k_line(time_from: first_point.first, time_to: last_point.first)
|
|
expect(JSON.parse(response.body)).to eq []
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'GET /api/v2/markets/tickers' do
|
|
after { delete_measurments("trades") }
|
|
|
|
context 'no trades executed yet' do
|
|
let(:expected_ticker) do
|
|
{ 'low' => '0.0', 'high' => '0.0',
|
|
'open' => '0.0', 'last' => '0.0',
|
|
'volume' => '0.0', 'vol' => '0.0', 'amount' => '0.0',
|
|
'avg_price' => '0.0', 'price_change_percent' => '+0.00%' }
|
|
end
|
|
|
|
it 'returns ticker of all markets' do
|
|
get '/api/v2/public/markets/tickers'
|
|
expect(response).to be_successful
|
|
expect(JSON.parse(response.body)['btcusd']['at']).not_to be_nil
|
|
expect(JSON.parse(response.body)['btcusd']['ticker']).to include(expected_ticker)
|
|
end
|
|
end
|
|
|
|
context 'single trade was executed' do
|
|
let!(:trade) { create(:trade, :btcusd, price: '5.0'.to_d, amount: '1.1'.to_d, total: '5.5'.to_d)}
|
|
let(:expected_ticker) do
|
|
{ 'low' => '5.0', 'high' => '5.0',
|
|
'open' => '5.0', 'last' => '5.0',
|
|
'volume' => '5.5', 'vol' => '5.5', 'amount' => '1.1',
|
|
'avg_price' => '5.0', 'price_change_percent' => '+0.00%' }
|
|
end
|
|
before do
|
|
trade.write_to_influx
|
|
end
|
|
|
|
it 'returns market tickers' do
|
|
get '/api/v2/public/markets/tickers'
|
|
expect(response).to be_successful
|
|
expect(JSON.parse(response.body)['btcusd']['at']).not_to be_nil
|
|
expect(JSON.parse(response.body)['btcusd']['ticker']).to include(expected_ticker)
|
|
end
|
|
end
|
|
|
|
context 'multiple trades were executed' do
|
|
let!(:trade1) { create(:trade, :btcusd, price: '5.0'.to_d, amount: '1.1'.to_d, total: '5.5'.to_d)}
|
|
let!(:trade2) { create(:trade, :btcusd, price: '6.0'.to_d, amount: '0.9'.to_d, total: '5.4'.to_d)}
|
|
|
|
let(:expected_ticker) do
|
|
{ 'low' => '5.0', 'high' => '6.0',
|
|
'open' => '5.0', 'last' => '6.0',
|
|
'vol' => '10.9', 'volume' => '10.9', 'amount' => '2.0',
|
|
'avg_price' => '5.45', 'price_change_percent' => '+20.00%' }
|
|
end
|
|
before do
|
|
trade1.write_to_influx
|
|
trade2.write_to_influx
|
|
end
|
|
|
|
it 'returns market tickers' do
|
|
get '/api/v2/public/markets/tickers'
|
|
expect(response).to be_successful
|
|
expect(JSON.parse(response.body)['btcusd']['at']).not_to be_nil
|
|
expect(JSON.parse(response.body)['btcusd']['ticker']).to include(expected_ticker)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'GET /api/v2/public/markets/:market/tickers' do
|
|
after { delete_measurments("trades") }
|
|
context 'no trades executed yet' do
|
|
let(:expected_ticker) do
|
|
{ 'low' => '0.0', 'high' => '0.0',
|
|
'open' => '0.0', 'last' => '0.0',
|
|
'volume' => '0.0', 'vol' => '0.0', 'amount' => '0.0',
|
|
'avg_price' => '0.0', 'price_change_percent' => '+0.00%' }
|
|
end
|
|
|
|
it 'returns market tickers' do
|
|
get '/api/v2/public/markets/btcusd/tickers'
|
|
expect(response).to be_successful
|
|
expect(JSON.parse(response.body)['ticker']).to include(expected_ticker)
|
|
end
|
|
|
|
context 'market name with dot' do
|
|
let!(:currency) { create(:currency, :xagm_cx) }
|
|
let!(:market) { create(:market, :xagm_cxusd) }
|
|
|
|
it 'returns information about specified market' do
|
|
get "/api/v2/public/markets/#{market.id}/tickers"
|
|
expect(response).to be_successful
|
|
expect(JSON.parse(response.body)['ticker']).to include(expected_ticker)
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'single trade was executed' do
|
|
let!(:trade) { create(:trade, :btcusd, price: '5.0'.to_d, amount: '1.1'.to_d, total: '5.5'.to_d)}
|
|
let(:expected_ticker) do
|
|
{ 'low' => '5.0', 'high' => '5.0',
|
|
'open' => '5.0', 'last' => '5.0',
|
|
'volume' => '5.5', 'vol' => '5.5', 'amount' => '1.1',
|
|
'avg_price' => '5.0', 'price_change_percent' => '+0.00%' }
|
|
end
|
|
before do
|
|
trade.write_to_influx
|
|
end
|
|
|
|
it 'returns market tickers' do
|
|
get '/api/v2/public/markets/btcusd/tickers'
|
|
expect(response).to be_successful
|
|
expect(JSON.parse(response.body)['ticker']).to include(expected_ticker)
|
|
end
|
|
end
|
|
|
|
context 'multiple trades were executed' do
|
|
let!(:trade1) { create(:trade, :btcusd, price: '5.0'.to_d, amount: '1.1'.to_d, total: '5.5'.to_d)}
|
|
let!(:trade2) { create(:trade, :btcusd, price: '6.0'.to_d, amount: '0.9'.to_d, total: '5.4'.to_d)}
|
|
|
|
# open = 6.0 because it takes last by default.
|
|
# to make it work correctly need to run k-line daemon.
|
|
let(:expected_ticker) do
|
|
{ 'low' => '5.0', 'high' => '6.0',
|
|
'open' => '5.0', 'last' => '6.0',
|
|
'vol' => '10.9', 'volume' => '10.9', 'amount' => '2.0',
|
|
'avg_price' => '5.45', 'price_change_percent' => '+20.00%' }
|
|
end
|
|
before do
|
|
trade1.write_to_influx
|
|
trade2.write_to_influx
|
|
end
|
|
|
|
it 'returns market tickers' do
|
|
get '/api/v2/public/markets/btcusd/tickers'
|
|
expect(response).to be_successful
|
|
expect(JSON.parse(response.body)['ticker']).to include(expected_ticker)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'GET /api/v2/public/markets/#{market}/trades' do
|
|
|
|
let(:member) do
|
|
create(:member, :level_3).tap do |m|
|
|
m.get_account(:btc).update_attributes(balance: 12.13, locked: 3.14)
|
|
m.get_account(:usd).update_attributes(balance: 2014.47, locked: 0)
|
|
end
|
|
end
|
|
|
|
let(:ask) do
|
|
create(
|
|
:order_ask,
|
|
:btcusd,
|
|
price: '12.32'.to_d,
|
|
volume: '123.12345678',
|
|
member: member
|
|
)
|
|
end
|
|
|
|
let(:bid) do
|
|
create(
|
|
:order_bid,
|
|
:btcusd,
|
|
price: '12.32'.to_d,
|
|
volume: '123.12345678',
|
|
member: member
|
|
)
|
|
end
|
|
|
|
let(:market) { :btcusd }
|
|
|
|
let!(:ask_trade) { create(:trade, :btcusd, maker_order: ask, created_at: 2.days.ago) }
|
|
let!(:bid_trade) { create(:trade, :btcusd, taker_order: bid, created_at: 1.day.ago) }
|
|
|
|
|
|
after do
|
|
delete_measurments('trades')
|
|
end
|
|
|
|
before do
|
|
ask_trade.write_to_influx
|
|
bid_trade.write_to_influx
|
|
end
|
|
|
|
it 'returns all recent trades' do
|
|
get "/api/v2/public/markets/#{market}/trades"
|
|
|
|
expect(response).to be_successful
|
|
expect(JSON.parse(response.body).size).to eq 2
|
|
end
|
|
|
|
context 'market name with dot' do
|
|
let!(:currency) { create(:currency, :xagm_cx) }
|
|
let!(:market) { create(:market, :xagm_cxusd) }
|
|
|
|
it 'returns information about specified market' do
|
|
get "/api/v2/public/markets/#{market.id}/trades"
|
|
expect(response).to be_successful
|
|
expect(JSON.parse(response.body).size).to eq 0
|
|
end
|
|
end
|
|
|
|
it 'returns 1 trade' do
|
|
get "/api/v2/public/markets/#{market}/trades", params: {limit: 1}
|
|
|
|
expect(response).to be_successful
|
|
expect(JSON.parse(response.body).size).to eq 1
|
|
end
|
|
|
|
it 'sorts trades in reverse creation order' do
|
|
get "/api/v2/public/markets/#{market}/trades"
|
|
|
|
expect(response).to be_successful
|
|
expect(JSON.parse(response.body).first['id']).to eq bid_trade.id
|
|
end
|
|
|
|
it 'gets trades by limit' do
|
|
trade = create(:trade, :btcusd, taker_order: bid, created_at: 6.hours.ago)
|
|
trade.write_to_influx
|
|
|
|
get "/api/v2/public/markets/#{market}/trades", params: { limit: 2, order_by: 'asc'}
|
|
|
|
expect(response).to be_successful
|
|
expect(JSON.parse(response.body).count).to eq 2
|
|
|
|
get "/api/v2/public/markets/#{market}/trades", params: { market: 'btcusd', limit: 3, order_by: 'asc' }
|
|
|
|
expect(response).to be_successful
|
|
expect(JSON.parse(response.body).count).to eq 3
|
|
end
|
|
|
|
it 'validates market param' do
|
|
api_get "/api/v2/public/markets/usdusd/trades"
|
|
expect(response).to have_http_status 422
|
|
expect(response).to include_api_error('public.market.doesnt_exist')
|
|
end
|
|
|
|
it 'validates limit param' do
|
|
get "/api/v2/public/markets/#{market}/trades", params: { limit: 1001 }
|
|
expect(response).to have_http_status 422
|
|
expect(response).to include_api_error('public.trade.invalid_limit')
|
|
end
|
|
end
|
|
end
|