diff --git a/src/ArbitragerImpl.ts b/src/ArbitragerImpl.ts index eeccce71..533c7ac6 100644 --- a/src/ArbitragerImpl.ts +++ b/src/ArbitragerImpl.ts @@ -101,12 +101,16 @@ export default class ArbitragerImpl implements Arbitrager { } this.log.info(t('FoundArbitrageOppotunity')); - this.log.info(t('SendingOrderTargettingQuote'), bestAsk); - await this.sendOrder(bestAsk, targetVolume, OrderType.Limit); - this.log.info(t('SendingOrderTargettingQuote'), bestBid); - await this.sendOrder(bestBid, targetVolume, OrderType.Limit); - this.status = 'Sent'; - await this.checkOrderState(); + try { + await this.sendOrder(bestAsk, targetVolume, OrderType.Limit); + await this.sendOrder(bestBid, targetVolume, OrderType.Limit); + this.status = 'Sent'; + await this.checkOrderState(); + } catch (ex) { + this.log.error(ex.message); + this.log.debug(ex.stack); + this.status = 'Order send/refresh failed'; + } this.log.info(t('SleepingAfterSend'), config.sleepAfterSend); this.activeOrders = []; await delay(config.sleepAfterSend); @@ -189,6 +193,7 @@ export default class ArbitragerImpl implements Arbitrager { } private async sendOrder(quote: Quote, targetVolume: number, orderType: OrderType): Promise { + this.log.info(t('SendingOrderTargettingQuote'), quote); const brokerConfig = _.find(this.configStore.config.brokers, x => x.broker === quote.broker) as BrokerConfig; const orderSide = quote.side === QuoteSide.Ask ? OrderSide.Buy : OrderSide.Sell; diff --git a/src/PositionServiceImpl.ts b/src/PositionServiceImpl.ts index 8dc2290a..9e0013f2 100644 --- a/src/PositionServiceImpl.ts +++ b/src/PositionServiceImpl.ts @@ -87,6 +87,9 @@ export default class PositionServiceImpl implements PositionService { return pos; }); this._positionMap = _(await Promise.all(promises)).map(p => [p.broker, p]).fromPairs().value(); + } catch (ex) { + this.log.error(ex.message); + this.log.debug(ex.stack); } finally { this.isRefreshing = false; this.log.debug('Finished refresh.'); diff --git a/src/__tests__/ArbitragerImpl.test.ts b/src/__tests__/ArbitragerImpl.test.ts index 1e74b76c..f06a4f33 100644 --- a/src/__tests__/ArbitragerImpl.test.ts +++ b/src/__tests__/ArbitragerImpl.test.ts @@ -303,6 +303,27 @@ describe('Arbitrager', () => { expect(arbitrager.status).toBe('MaxRetryCount breached'); }); + test('Send throws', async () => { + config.maxRetryCount = 3; + spreadAnalyzer.analyze.mockImplementation(() => { + return { + bestBid: new Quote(Broker.Quoine, QuoteSide.Bid, 600, 4), + bestAsk: new Quote(Broker.Coincheck, QuoteSide.Ask, 500, 1), + invertedSpread: 100, + availableVolume: 1, + targetVolume: 1, + targetProfit: 100 + }; + }); + baRouter.send = () => { throw new Error('Mock refresh error.'); }; + const arbitrager = new ArbitragerImpl(quoteAggregator, configStore, + positionService, baRouter, spreadAnalyzer); + positionService.isStarted = true; + await arbitrager.start(); + await quoteAggregator.onQuoteUpdated([]); + expect(arbitrager.status).toBe('Order send/refresh failed'); + }); + test('Send and refresh throws', async () => { config.maxRetryCount = 3; spreadAnalyzer.analyze.mockImplementation(() => { diff --git a/src/__tests__/PositionServiceImpl.test.ts b/src/__tests__/PositionServiceImpl.test.ts index e9b49a17..eafb4b07 100644 --- a/src/__tests__/PositionServiceImpl.test.ts +++ b/src/__tests__/PositionServiceImpl.test.ts @@ -50,6 +50,16 @@ describe('Position Service', () => { expect(qPos.allowedShortSize).toBe(0.2); }); + test('positions throws', async () => { + const baRouterThrows = { getBtcPosition: async () => { throw new Error('Mock refresh error.'); } }; + const ps = new PositionServiceImpl(configStore, baRouterThrows); + ps.print(); + await ps.start(); + expect(ps.positionMap).toBeUndefined(); + expect(ps.netExposure).toBe(0); + await ps.stop(); + }); + test('positions smaller than minSize', async () => { const baRouter = { getBtcPosition: broker => broker === Broker.Quoine ? 0.000002 : -0.3 diff --git a/src/stringResources.ts b/src/stringResources.ts index 103f6e47..49550800 100644 --- a/src/stringResources.ts +++ b/src/stringResources.ts @@ -1,3 +1,4 @@ +// tslint:disable:max-line-length export const en = { ArbitragerThreadHasBeenStopped: 'Arbitrager thread has been stopped. Please hit Enter to close this window.', AtLeastTwoBrokersMustBeEnabled: 'At least two brokers must be enabled.', @@ -10,7 +11,7 @@ export const en = { BuyLegIsNotFilledYetPendingSizeIs: '>>Buy leg is not filled yet. Pending size is %s.', CheckingIfBothLegsAreDoneOrNot: '>>Checking if both legs are done or not...', ExpectedProfit: 'Expected profit', - FailedToGetASpreadAnalysisResult: 'Failed to get a spread analysis result. %s', + FailedToGetASpreadAnalysisResult: 'Failed to get a spread analysis result. Check maxLongPosition and maxShortPosition in the broker configs. %s', FoundArbitrageOppotunity: '>>Found arbitrage oppotunity.', FoundInvertedQuotes: 'Found inverted quotes.', LongAllowed: 'LongAllowed', @@ -53,7 +54,7 @@ export const ja = { BuyLegIsNotFilledYetPendingSizeIs: '>>買いオーダー未約定。残り数量%s', CheckingIfBothLegsAreDoneOrNot: '>>両方のオーダーが約定したか確認中...', ExpectedProfit: '予想収益  ', - FailedToGetASpreadAnalysisResult: 'スプレッド解析結果の取得に失敗しました。 %s', + FailedToGetASpreadAnalysisResult: 'スプレッド解析結果の取得に失敗しました。取引所設定のmaxLongPosition, maxShortPositionが十分に大きいか確認してください。 %s', FoundArbitrageOppotunity: '>>裁定機会を発見。', FoundInvertedQuotes: 'スプレッドの逆転を発見。', LongAllowed: '買い試行許可',