Skip to content

Commit

Permalink
Merge branch 'master' into #633-load-open-orders
Browse files Browse the repository at this point in the history
Conflicts:
	src/modules/market/selectors/market.js
	src/selectors.js
  • Loading branch information
priecint committed Aug 3, 2016
2 parents d4aff34 + 5513483 commit 51f0dbd
Show file tree
Hide file tree
Showing 43 changed files with 664 additions and 771 deletions.
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@
"partial:index_filename": "[ $NODE_ENV != production ] && echo './build/index.html' || echo \"./build/index-$npm_package_version.html\""
},
"dependencies": {
"augur-ui-react-components": "3.0.22",
"augur.js": "1.9.16",
"augur-ui-react-components": "3.0.31",
"augur.js": "1.9.23",
"bignumber.js": "2.4.0",
"memoizerific": "1.8.4",
"npm-check-updates": "^2.7.1",
Expand Down Expand Up @@ -85,13 +85,13 @@
"eslint-plugin-jsx-a11y": "1.5.5",
"eslint-plugin-react": "5.2.2",
"exorcist": "0.4.0",
"firebase-tools": "3.0.4",
"firebase-tools": "3.0.6",
"inline-source-cli": "1.1.1",
"istanbul": "1.0.0-alpha.2",
"less": "2.7.1",
"mocha": "2.5.3",
"mocha": "3.0.0",
"mocha-lcov-reporter": "1.2.0",
"npm-check-updates": "2.7.2",
"npm-check-updates": "2.8.0",
"onchange": "2.5.0",
"proxyquire": "1.7.10",
"redux-mock-store": "1.1.2",
Expand Down
4 changes: 2 additions & 2 deletions src/modules/create-market/actions/submit-new-market.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import makeDescription from '../../../utils/make-description';
import { BRANCH_ID } from '../../app/constants/network';
import { BINARY, CATEGORICAL, SCALAR } from '../../markets/constants/market-types';
import { SUCCESS, FAILED, CREATING_MARKET } from '../../transactions/constants/statuses';
import { CATEGORICAL_OUTCOMES_SEPARATOR, CATEGORICAL_OUTCOME_SEPARATOR } from '../../markets/constants/market-outcomes';

import AugurJS from '../../../services/augurjs';

Expand Down Expand Up @@ -35,7 +35,7 @@ export function createMarket(transactionID, newMarket) {
newMarket.minValue = 1;
newMarket.maxValue = 2;
newMarket.numOutcomes = newMarket.outcomes.length;
newMarket.formattedDescription = makeDescription(newMarket);
newMarket.formattedDescription = newMarket.description + CATEGORICAL_OUTCOMES_SEPARATOR + newMarket.outcomes.map(outcome => outcome.name).join(CATEGORICAL_OUTCOME_SEPARATOR);
} else {
console.warn('createMarket unsupported type:', newMarket.type);
return;
Expand Down
44 changes: 16 additions & 28 deletions src/modules/market/selectors/market.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,23 @@ import { toggleTag } from '../../markets/actions/toggle-tag';
import store from '../../../store';

import { selectMarketLink } from '../../link/selectors/links';
import { selectPositionsSummary } from '../../positions/selectors/positions-summary';
import selectUserOpenOrders from '../../user-open-orders/selectors/user-open-orders';
import selectUserOpenOrdersSummary from '../../user-open-orders/selectors/user-open-orders-summary';

import { selectPriceTimeSeries } from '../../market/selectors/price-time-series';

import { selectPositionFromOutcomeAccountTrades } from '../../positions/selectors/position';

import { selectAggregateOrderBook, selectTopBid, selectTopAsk } from '../../bids-asks/selectors/select-order-book';

import { generateTrade, generateTradeSummary } from '../../market/selectors/helpers/generate-trade';
import { generateOutcomePositionSummary, generateMarketsPositionsSummary } from '../../positions/selectors/positions-summary';

export default function () {
const { selectedMarketID } = store.getState();
return selectMarket(selectedMarketID);
}

export const selectMarket = (marketID) => {
const { marketsData, favorites, reports, outcomes, accountTrades, tradesInProgress, blockchain, priceHistory, marketOrderBooks } = store.getState();
const { marketsData, favorites, reports, outcomesData, accountTrades, tradesInProgress, blockchain, priceHistory, marketOrderBooks } = store.getState();

if (!marketID || !marketsData || !marketsData[marketID]) {
return {};
Expand All @@ -70,10 +68,10 @@ export const selectMarket = (marketID) => {
isMarketDataOpen(marketsData[marketID], blockchain && blockchain.currentBlockNumber),

!!favorites[marketID],
outcomes[marketID],
outcomesData[marketID],

reports[marketsData[marketID].eventID],
accountTrades[marketID],
(accountTrades || {})[marketID],
tradesInProgress[marketID],

// the reason we pass in the date parts broken up like this, is because date objects are never equal, thereby always triggering re-assembly, and never hitting the memoization cache
Expand All @@ -100,7 +98,7 @@ export const assembleMarket = memoizerific(1000)((
marketPriceHistory,
isOpen,
isFavorite,
marketOutcomes,
marketOutcomesData,
marketReport,
marketAccountTrades,
marketTradeInProgress,
Expand All @@ -117,7 +115,6 @@ export const assembleMarket = memoizerific(1000)((
id: marketID
};

market.type = marketData.type;
switch (market.type) {
case BINARY:
market.isBinary = true;
Expand Down Expand Up @@ -168,31 +165,23 @@ export const assembleMarket = memoizerific(1000)((
market.outcomes = [];

let marketTradeOrders = [];
const positions = { qtyShares: 0, totalValue: 0, totalCost: 0, list: [] };

market.outcomes = Object.keys(marketOutcomes || {}).map(outcomeID => {
const outcomeData = marketOutcomes[outcomeID];
market.outcomes = Object.keys(marketOutcomesData || {}).map(outcomeID => {
const outcomeData = marketOutcomesData[outcomeID];
const outcomeTradeInProgress = marketTradeInProgress && marketTradeInProgress[outcomeID];

const outcome = {
...outcomeData,
id: outcomeID,
marketID,
lastPrice: formatEther(outcomeData.price || 0, { positiveSign: false }),
lastPricePercent: formatPercent((outcomeData.price || 0) * 100, { positiveSign: false })
lastPrice: formatEther(parseFloat(outcomeData.price) || 0, { positiveSign: false })
};

outcome.lastPricePercent = formatPercent(outcome.lastPrice.value * 100, { positiveSign: false });

outcome.trade = generateTrade(market, outcome, outcomeTradeInProgress);

if (marketAccountTrades && marketAccountTrades[outcomeID]) {
outcome.position = selectPositionFromOutcomeAccountTrades(marketAccountTrades[outcomeID], outcome.price);
if (outcome.position && outcome.position.qtyShares && outcome.position.qtyShares.value) {
positions.qtyShares += outcome.position.qtyShares.value;
positions.totalValue += outcome.position.totalValue.value || 0;
positions.totalCost += outcome.position.totalCost.value || 0;
positions.list.push(outcome);
}
}
outcome.position = generateOutcomePositionSummary((marketAccountTrades || {})[outcomeID], outcome.lastPrice.value);

const orderBook = selectAggregateOrderBook(outcome.id, marketOrderBooks);
outcome.orderBook = orderBook;
Expand Down Expand Up @@ -222,13 +211,12 @@ export const assembleMarket = memoizerific(1000)((
market.userOpenOrdersSummary = selectUserOpenOrdersSummary(market.outcomes);

market.tradeSummary = generateTradeSummary(marketTradeOrders);
market.positionsSummary = selectPositionsSummary(
positions.list.length,
positions.qtyShares,
positions.totalValue,
positions.totalCost);

market.positionOutcomes = positions.list;
market.positionsSummary = generateMarketsPositionsSummary([market]);
if (market.positionsSummary) {
market.positionOutcomes = market.positionsSummary.positionOutcomes;
delete market.positionsSummary.positionOutcomes;
}

return market;
});
129 changes: 2 additions & 127 deletions src/modules/markets/actions/load-markets-info.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import * as AugurJS from '../../../services/augurjs';

// import { BRANCH_ID } from '../../app/constants/network';
import { BINARY, CATEGORICAL, SCALAR } from '../../markets/constants/market-types';
import { CATEGORICAL_OUTCOMES_SEPARATOR, CATEGORICAL_OUTCOME_SEPARATOR, BINARY_NO_ID, BINARY_YES_ID, SCALAR_DOWN_ID, SCALAR_UP_ID } from '../../markets/constants/market-outcomes';

import { updateMarketsData } from '../../markets/actions/update-markets-data';
import { updateOutcomesData } from '../../markets/actions/update-outcomes-data';

export function loadMarketsInfo(marketIDs, cb) {
return (dispatch, getState) => {
Expand All @@ -16,132 +11,12 @@ export function loadMarketsInfo(marketIDs, cb) {
AugurJS.batchGetMarketInfo(marketIDs, (err, marketsData) => {
if (err) {
console.error('ERROR loadMarketsInfo()', err);
// we purposely don't return here so that the loop below runs and sets isLoadedMarketInfo
return;
}

const finalMarketsData = {};
const finalOutcomesData = {};

let marketData;

// it's important to loop through the original marketIDs so that unloaded markets can still be marked as isLoadedMarketInfo and avoid infinite recursion later on
marketIDs.forEach(marketID => {

marketData = marketsData[marketID] || {};

// parse out event, currently we only support single event markets, no combinatorial
parseEvent(marketData, marketID);

// transform array of outcomes into an object and add their names
finalOutcomesData[marketID] = parseOutcomes(marketData);
if (finalOutcomesData[marketID] === undefined) { // Data object is mal-formed if outcomes are unable to be parsed.
marketData.isMalFormed = true;
}

// mark that details have been loaded
marketData.isLoadedMarketInfo = true;

// save market (without outcomes)
finalMarketsData[marketID] = marketData;
});

dispatch(updateMarketsData(finalMarketsData));
dispatch(updateOutcomesData(finalOutcomesData));
dispatch(updateMarketsData(marketsData));

cb && cb();
});
};

function parseEvent(marketData, marketID) {
if (!marketData.events || marketData.events.length !== 1) {
console.warn('Market does not have correct number of events:', marketID, marketData);
delete marketData.events;
return;
}

const event = marketData.events[0];
marketData.eventID = event.id;
marketData.minValue = event.minValue;
marketData.maxValue = event.maxValue;
marketData.numOutcomes = event.numOutcomes;
marketData.reportedOutcome = event.outcome;
delete marketData.events;
}

function parseOutcomes(marketData, marketID) {
if (!marketData.outcomes || !marketData.outcomes.length) {
console.warn('Market does not have outcomes:', marketID, marketData);
return undefined;
}

let outcomes;
let splitDescription;
let categoricalOutcomeNames;

switch (marketData.type) {
case BINARY:
outcomes = marketData.outcomes.map(outcome => {
if (outcome.id === BINARY_NO_ID) {
outcome.name = 'No';
} else if (outcome.id === BINARY_YES_ID) {
outcome.name = 'Yes';
} else {
console.warn('Invalid outcome ID for binary market:', outcome, marketID, marketData);
}
return outcome;
});
break;

case CATEGORICAL:
// parse outcome names from description
splitDescription = marketData.description.split(CATEGORICAL_OUTCOMES_SEPARATOR);
if (splitDescription.length < 2) {
console.warn('Missing outcome names in description for categorical market:', marketID, marketData);
return undefined;
}

// parse individual outcomes from outcomes string
categoricalOutcomeNames = splitDescription.pop().split(CATEGORICAL_OUTCOME_SEPARATOR);
if (categoricalOutcomeNames.length !== marketData.outcomes.length) {
console.warn('Number of outcomes parsed from description do not match number of outcomes in market for for categorical market:', marketID, marketData);
return undefined;
}

// add names to outcomes
outcomes = marketData.outcomes.map((outcome, i) => {
outcome.name = categoricalOutcomeNames[i].toString().trim();
return outcome;
});

// update market description to exclude outcome names
marketData.description = splitDescription.join();
break;

case SCALAR:
outcomes = marketData.outcomes.map(outcome => {
if (outcome.id === SCALAR_DOWN_ID) {
outcome.name = '⇩';
} else if (outcome.id === SCALAR_UP_ID) {
outcome.name = '⇧';
} else {
console.warn('Invalid outcome ID for scalar market:', marketID, outcome, marketData);
}
return outcome;
});
break;

default:
console.warn('Unknown market type:', marketID, marketData.type, marketData);
outcomes = undefined;
break;
}

delete marketData.outcomes;

return outcomes.reduce((p, outcome) => {
p[outcome.id] = outcome;
delete outcome.id;
return p;
}, {});
}
}
5 changes: 0 additions & 5 deletions src/modules/markets/actions/update-markets-data.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
export const UPDATE_MARKETS_DATA = 'UPDATE_MARKETS_DATA';
export const UPDATE_MARKET_DATA = 'UPDATE_MARKET_DATA';

export function updateMarketsData(marketsData) {
return { type: UPDATE_MARKETS_DATA, marketsData };
}

export function updateMarketData(marketData) {
return { type: UPDATE_MARKET_DATA, marketData };
}
5 changes: 0 additions & 5 deletions src/modules/markets/actions/update-outcomes-data.js

This file was deleted.

61 changes: 50 additions & 11 deletions src/modules/markets/reducers/markets-data.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,62 @@
import { UPDATE_MARKETS_DATA, UPDATE_MARKET_DATA } from '../../markets/actions/update-markets-data';
import { UPDATE_MARKETS_DATA } from '../../markets/actions/update-markets-data';

import { CATEGORICAL } from '../../markets/constants/market-types';
import { CATEGORICAL_OUTCOMES_SEPARATOR } from '../../markets/constants/market-outcomes';

export default function (marketsData = {}, action) {
switch (action.type) {
case UPDATE_MARKETS_DATA:
return {
...marketsData,
...action.marketsData
};

case UPDATE_MARKET_DATA:
return {
...marketsData,
[action.marketData.id]: {
...marketsData[action.marketData.id],
...action.marketData
}
...processMarketsData(action.marketsData, marketsData)
};

default:
return marketsData;
}
}

function processMarketsData(newMarketsData, existingMarketsData) {

// it's important to loop through the original marketIDs so that unloaded markets can still be marked as isLoadedMarketInfo and avoid infinite recursion later on
return Object.keys(newMarketsData).reduce((p, marketID) => {
const marketData = {
...existingMarketsData[marketID],
...newMarketsData[marketID]
};

// clean description
if (marketData.type === CATEGORICAL) {
marketData.description = marketData.description.split(CATEGORICAL_OUTCOMES_SEPARATOR).slice(0, -1).join();
}

// delete outcomes
delete marketData.outcomes;

// parse out event, currently we only support single event markets, no combinatorial
parseEvent(marketData);

// mark whether details have been loaded
marketData.isLoadedMarketInfo = !!marketData.type;

// save market (without outcomes)
p[marketID] = marketData;

return p;
}, {});

function parseEvent(marketData) {
if (!marketData.events || marketData.events.length !== 1) {
delete marketData.events;
return;
}

const event = marketData.events[0];
marketData.eventID = event.id;
marketData.minValue = event.minValue;
marketData.maxValue = event.maxValue;
marketData.numOutcomes = event.numOutcomes;
marketData.reportedOutcome = event.outcome;
delete marketData.events;
}
}
Loading

0 comments on commit 51f0dbd

Please sign in to comment.