be-components 6.2.1 → 6.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/Competition/components/CompetitionPlay.js +8 -1
- package/lib/commonjs/Competition/components/CompetitionPlay.js.map +1 -1
- package/lib/commonjs/Competition/components/MarketsCard.js +1 -0
- package/lib/commonjs/Competition/components/MarketsCard.js.map +1 -1
- package/lib/commonjs/Components/Icons.js +49 -0
- package/lib/commonjs/Components/Icons.js.map +1 -1
- package/lib/commonjs/MarketComponents/api/index.js +189 -0
- package/lib/commonjs/MarketComponents/api/index.js.map +1 -1
- package/lib/commonjs/MarketComponents/components/CreateMarketForm.js +736 -0
- package/lib/commonjs/MarketComponents/components/CreateMarketForm.js.map +1 -0
- package/lib/commonjs/MarketComponents/components/WeightProgress.js +53 -0
- package/lib/commonjs/MarketComponents/components/WeightProgress.js.map +1 -0
- package/lib/commonjs/MarketComponents/index.js +2 -0
- package/lib/commonjs/MarketComponents/index.js.map +1 -1
- package/lib/commonjs/MarketMaker/api/index.js +3 -0
- package/lib/commonjs/MarketMaker/api/index.js.map +1 -1
- package/lib/commonjs/Poll/components/PollCard.js +3 -0
- package/lib/commonjs/Poll/components/PollCard.js.map +1 -1
- package/lib/module/Competition/components/CompetitionPlay.js +8 -1
- package/lib/module/Competition/components/CompetitionPlay.js.map +1 -1
- package/lib/module/Competition/components/MarketsCard.js +1 -0
- package/lib/module/Competition/components/MarketsCard.js.map +1 -1
- package/lib/module/Components/Icons.js +49 -0
- package/lib/module/Components/Icons.js.map +1 -1
- package/lib/module/MarketComponents/api/index.js +189 -0
- package/lib/module/MarketComponents/api/index.js.map +1 -1
- package/lib/module/MarketComponents/components/CreateMarketForm.js +727 -0
- package/lib/module/MarketComponents/components/CreateMarketForm.js.map +1 -0
- package/lib/module/MarketComponents/components/WeightProgress.js +45 -0
- package/lib/module/MarketComponents/components/WeightProgress.js.map +1 -0
- package/lib/module/MarketComponents/index.js +2 -0
- package/lib/module/MarketComponents/index.js.map +1 -1
- package/lib/module/MarketMaker/api/index.js +3 -0
- package/lib/module/MarketMaker/api/index.js.map +1 -1
- package/lib/module/Poll/components/PollCard.js +3 -0
- package/lib/module/Poll/components/PollCard.js.map +1 -1
- package/lib/typescript/lib/commonjs/Competition/components/CompetitionPlay.d.ts.map +1 -1
- package/lib/typescript/lib/commonjs/Competition/components/MarketsCard.d.ts.map +1 -1
- package/lib/typescript/lib/commonjs/Components/Icons.d.ts +10 -0
- package/lib/typescript/lib/commonjs/Components/Icons.d.ts.map +1 -1
- package/lib/typescript/lib/commonjs/MarketComponents/api/index.d.ts +6 -0
- package/lib/typescript/lib/commonjs/MarketComponents/api/index.d.ts.map +1 -1
- package/lib/typescript/lib/commonjs/MarketComponents/components/CreateMarketForm.d.ts +20 -0
- package/lib/typescript/lib/commonjs/MarketComponents/components/CreateMarketForm.d.ts.map +1 -0
- package/lib/typescript/lib/commonjs/MarketComponents/components/WeightProgress.d.ts +8 -0
- package/lib/typescript/lib/commonjs/MarketComponents/components/WeightProgress.d.ts.map +1 -0
- package/lib/typescript/lib/commonjs/MarketComponents/index.d.ts +1 -0
- package/lib/typescript/lib/commonjs/MarketMaker/api/index.d.ts.map +1 -1
- package/lib/typescript/lib/commonjs/Poll/components/PollCard.d.ts.map +1 -1
- package/lib/typescript/lib/module/Competition/components/CompetitionPlay.d.ts.map +1 -1
- package/lib/typescript/lib/module/Competition/components/MarketsCard.d.ts.map +1 -1
- package/lib/typescript/lib/module/Components/Icons.d.ts +10 -0
- package/lib/typescript/lib/module/Components/Icons.d.ts.map +1 -1
- package/lib/typescript/lib/module/MarketComponents/api/index.d.ts +6 -0
- package/lib/typescript/lib/module/MarketComponents/api/index.d.ts.map +1 -1
- package/lib/typescript/lib/module/MarketComponents/components/CreateMarketForm.d.ts +20 -0
- package/lib/typescript/lib/module/MarketComponents/components/CreateMarketForm.d.ts.map +1 -0
- package/lib/typescript/lib/module/MarketComponents/components/WeightProgress.d.ts +8 -0
- package/lib/typescript/lib/module/MarketComponents/components/WeightProgress.d.ts.map +1 -0
- package/lib/typescript/lib/module/MarketComponents/index.d.ts +2 -0
- package/lib/typescript/lib/module/MarketComponents/index.d.ts.map +1 -1
- package/lib/typescript/lib/module/MarketMaker/api/index.d.ts.map +1 -1
- package/lib/typescript/lib/module/Poll/components/PollCard.d.ts.map +1 -1
- package/lib/typescript/src/Competition/components/MarketsCard.d.ts.map +1 -1
- package/lib/typescript/src/Components/Icons.d.ts +2 -0
- package/lib/typescript/src/Components/Icons.d.ts.map +1 -1
- package/lib/typescript/src/MarketComponents/api/index.d.ts +6 -0
- package/lib/typescript/src/MarketComponents/api/index.d.ts.map +1 -1
- package/lib/typescript/src/MarketComponents/components/CreateMarketForm.d.ts +27 -0
- package/lib/typescript/src/MarketComponents/components/CreateMarketForm.d.ts.map +1 -0
- package/lib/typescript/src/MarketComponents/components/WeightProgress.d.ts +12 -0
- package/lib/typescript/src/MarketComponents/components/WeightProgress.d.ts.map +1 -0
- package/lib/typescript/src/MarketComponents/index.d.ts +21 -0
- package/lib/typescript/src/MarketComponents/index.d.ts.map +1 -1
- package/lib/typescript/src/MarketMaker/api/index.d.ts +1 -1
- package/lib/typescript/src/MarketMaker/api/index.d.ts.map +1 -1
- package/lib/typescript/src/Poll/components/PollCard.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/Competition/components/CompetitionPlay.tsx +6 -6
- package/src/Competition/components/MarketsCard.tsx +1 -0
- package/src/Components/Icons.tsx +26 -0
- package/src/MarketComponents/api/index.ts +166 -3
- package/src/MarketComponents/components/CreateMarketForm.tsx +444 -0
- package/src/MarketComponents/components/WeightProgress.tsx +32 -0
- package/src/MarketComponents/index.tsx +2 -0
- package/src/MarketMaker/api/index.ts +2 -1
- package/src/Poll/components/PollCard.tsx +1 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import { APIOverrides } from "../../ApiOverrides"
|
|
3
3
|
import type { AthleteProps, AthleteStatProps, BestAvailableOrderProps, BestAvailableResponseProps, ContestStatProps, EventOrderStatProps, EventProps, ExternalPriceProps, LeagueProps, MarketProps, MarketSideOptionProps, MarketStatsProps, MatchProps, MyPlayerProps, OrderProps, PodcastProps, PositionProps, PublicPlayerProps, TeamProps, TournamentProps, TradeProps } from "../../types"
|
|
4
|
-
import moment from 'moment-mini';
|
|
4
|
+
import moment, { type Moment } from 'moment-mini';
|
|
5
|
+
import { MarketMaketHelpers } from '../../MarketMaker/api';
|
|
5
6
|
|
|
6
7
|
let EVENT_SVC_API = ''
|
|
7
8
|
let AUTH_SVC_API = ''
|
|
@@ -526,6 +527,21 @@ const MarketComponentHelpers = {
|
|
|
526
527
|
}
|
|
527
528
|
return (p/(1-(p/100)))*-1
|
|
528
529
|
},
|
|
530
|
+
getSideIds: (contest_type:string, so:MarketSideOptionProps, market?:MarketProps, event?:EventProps, tournament?:TournamentProps, match?:MatchProps, athlete?:AthleteProps, team?:TeamProps) => {
|
|
531
|
+
if(!market){ return undefined }
|
|
532
|
+
switch(contest_type){
|
|
533
|
+
case 'team':
|
|
534
|
+
if(!event) return undefined
|
|
535
|
+
return MarketComponentHelpers.getTeamEventSideIds(event, market, so, athlete, team)
|
|
536
|
+
case 'tournament':
|
|
537
|
+
if(!tournament){ return undefined }
|
|
538
|
+
return MarketComponentHelpers.getTournamentSideIds(market, so, athlete, team);
|
|
539
|
+
case 'match':
|
|
540
|
+
if(!match){ return undefined }
|
|
541
|
+
return MarketComponentHelpers.getMatchSideIds(match, so)
|
|
542
|
+
default: return undefined
|
|
543
|
+
}
|
|
544
|
+
},
|
|
529
545
|
getTournamentSideIds: (market:MarketProps, side_option:MarketSideOptionProps, athlete?:AthleteProps, team?:TeamProps) => {
|
|
530
546
|
const o_side = market.side_options.find(so => so.side != side_option.side);
|
|
531
547
|
if(!o_side){ return undefined }
|
|
@@ -544,6 +560,46 @@ const MarketComponentHelpers = {
|
|
|
544
560
|
default: return undefined
|
|
545
561
|
}
|
|
546
562
|
},
|
|
563
|
+
pretendFulfillOrder: (order:BestAvailableOrderProps | OrderProps, stake?:number):OrderProps => {
|
|
564
|
+
let fill_stake = stake ?? order.open_amt
|
|
565
|
+
if(fill_stake > order.open_amt){
|
|
566
|
+
fill_stake = order.open_amt
|
|
567
|
+
}
|
|
568
|
+
order.open_amt -= fill_stake
|
|
569
|
+
order.called_amt = fill_stake
|
|
570
|
+
|
|
571
|
+
let position:PositionProps = {
|
|
572
|
+
position_id: '',
|
|
573
|
+
order_id: order.order_id,
|
|
574
|
+
stake: fill_stake,
|
|
575
|
+
probability: order.probability,
|
|
576
|
+
odds: order.odds,
|
|
577
|
+
status: 'inprogress',
|
|
578
|
+
winnings: 0, net_winnings: 0,
|
|
579
|
+
potential_winnings: MarketComponentHelpers.calcPotentialWinnings(fill_stake, order.odds),
|
|
580
|
+
original_stake: fill_stake,
|
|
581
|
+
cash_rcvd: 0,
|
|
582
|
+
delayed_cash: 0,
|
|
583
|
+
in_sale_order: 0,
|
|
584
|
+
commission: 0
|
|
585
|
+
}
|
|
586
|
+
return {
|
|
587
|
+
...order,
|
|
588
|
+
be_type: 'market',
|
|
589
|
+
order_type:'limit',
|
|
590
|
+
collar_pct: 0,
|
|
591
|
+
position_ids: [],
|
|
592
|
+
market_type: 'FOR_MONEY',
|
|
593
|
+
status: 'approved',
|
|
594
|
+
available_for_parlays:false,
|
|
595
|
+
resolution_status: 'inprogress',
|
|
596
|
+
commission_pct: 0,
|
|
597
|
+
side_type: order.side_type as 'team'|'side'|'athlete',
|
|
598
|
+
buy_sell_ind: order.buy_sell_ind as 'buy'|'sell',
|
|
599
|
+
event_type: order.event_type as 'team'|'tournament'|'match',
|
|
600
|
+
positions: [position]
|
|
601
|
+
}
|
|
602
|
+
},
|
|
547
603
|
prettyKey : (key?:string) => {
|
|
548
604
|
try {
|
|
549
605
|
if(!key){ return '' }
|
|
@@ -751,6 +807,113 @@ const MarketComponentHelpers = {
|
|
|
751
807
|
}
|
|
752
808
|
})
|
|
753
809
|
return { contest_title, o_side_label, trade_side_label }
|
|
754
|
-
|
|
755
|
-
|
|
810
|
+
},
|
|
811
|
+
setMarket: (unit_size:number, contest_type:'team'|'tournament'|'match',best_available:BestAvailableOrderProps[], external_prices:ExternalPriceProps[], o_side_margin:number, trade_side_margin:number, market?:MarketProps, event?:EventProps, tournament?:TournamentProps, match?:MatchProps, athlete?:AthleteProps, team?:TeamProps) => {
|
|
812
|
+
let orders:OrderProps[] = []
|
|
813
|
+
let expire_datetime:Moment | undefined = undefined
|
|
814
|
+
if(!market){ return [] }
|
|
815
|
+
market.side_options.map(so => {
|
|
816
|
+
let side_id_response:any = undefined
|
|
817
|
+
switch(contest_type){
|
|
818
|
+
case 'team':
|
|
819
|
+
if(!event){ return }
|
|
820
|
+
expire_datetime = moment(event.scheduled_datetime);
|
|
821
|
+
side_id_response = MarketComponentHelpers.getTeamEventSideIds(event, market, so);
|
|
822
|
+
break
|
|
823
|
+
case 'tournament':
|
|
824
|
+
if(!tournament){ return }
|
|
825
|
+
expire_datetime = moment(tournament.scheduled_datetime);
|
|
826
|
+
side_id_response = MarketComponentHelpers.getTournamentSideIds(market, so, athlete, team);
|
|
827
|
+
break
|
|
828
|
+
case 'match':
|
|
829
|
+
if(!match){ return }
|
|
830
|
+
expire_datetime = moment(match.scheduled_datetime);
|
|
831
|
+
side_id_response = MarketComponentHelpers.getMatchSideIds(match, so);
|
|
832
|
+
break
|
|
833
|
+
default: return
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
if(!side_id_response){ return }
|
|
837
|
+
let ba = best_available.find(ba => ba.side == so.side)
|
|
838
|
+
let o_ba = best_available.find(ba => ba.side != so.side);
|
|
839
|
+
if(ba && o_ba){
|
|
840
|
+
let ba_trade = MarketMaketHelpers.getTradeFromAvailableOrder(ba, side_id_response.reversed_side_id);
|
|
841
|
+
let ba_order = MarketMaketHelpers.getOrderFromTrade(ba_trade, 10, ba.order_id);
|
|
842
|
+
let ba_title = MarketComponentHelpers.getOrderTitle(ba_order, market, event, tournament, match, athlete, team);
|
|
843
|
+
|
|
844
|
+
if(!ba_title){ return }
|
|
845
|
+
return orders.push({ ...ba_order, title: ba_title })
|
|
846
|
+
}
|
|
847
|
+
let ep = external_prices.find(p => p.side == so.side);
|
|
848
|
+
let o_ep = external_prices.find(p => p.side != so.side);
|
|
849
|
+
if(ep && o_ep){
|
|
850
|
+
let ep_trade = MarketMaketHelpers.getTradeFromPrice(ep, side_id_response.reversed_side_id);
|
|
851
|
+
let ep_order = MarketMaketHelpers.getOrderFromTrade(ep_trade, 10);
|
|
852
|
+
let ep_title = MarketComponentHelpers.getOrderTitle(ep_order, market, event, tournament, match, athlete, team);
|
|
853
|
+
if(!ep_title){ return }
|
|
854
|
+
return orders.push({ ...ep_order, title: ep_title })
|
|
855
|
+
}
|
|
856
|
+
return
|
|
857
|
+
})
|
|
858
|
+
|
|
859
|
+
if(orders.length != 2){ return [] }
|
|
860
|
+
|
|
861
|
+
//OK!! Lets figured out the buffer odds!
|
|
862
|
+
let no_vig_trade_price = .5
|
|
863
|
+
let no_vig_o_price = .5
|
|
864
|
+
let no_vig_data = MarketMaketHelpers.getNoVigPrice(external_prices, market);
|
|
865
|
+
if(no_vig_data){
|
|
866
|
+
no_vig_o_price = no_vig_data.o_side_prob
|
|
867
|
+
no_vig_trade_price = no_vig_data.trade_side_prob
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
//Now lets add a buffer to each one based on the margin provided!
|
|
871
|
+
let margin = o_side_margin + trade_side_margin
|
|
872
|
+
let o_side_weight = o_side_margin / margin
|
|
873
|
+
let trade_side_weight = trade_side_margin / margin
|
|
874
|
+
no_vig_trade_price -= (margin * trade_side_weight)
|
|
875
|
+
let novig_trade_side_odds = Math.round(MarketMaketHelpers.calcAmericanOddsFromProbability(no_vig_trade_price))
|
|
876
|
+
|
|
877
|
+
no_vig_o_price -= (margin * o_side_weight)
|
|
878
|
+
|
|
879
|
+
let novig_o_side_odds = Math.round(MarketMaketHelpers.calcAmericanOddsFromProbability(no_vig_o_price))
|
|
880
|
+
|
|
881
|
+
//OK!!! Now lets add the propbabilities to the orders!
|
|
882
|
+
let trade_side_order = orders.find(o => o.side == market.trade_side);
|
|
883
|
+
let o_side_order = orders.find(o => o.side != market.trade_side);
|
|
884
|
+
if(!trade_side_order || !o_side_order){ return [] }
|
|
885
|
+
|
|
886
|
+
let higher_probability_order = no_vig_trade_price >= no_vig_o_price ? 'trade' : 'other'
|
|
887
|
+
let trade_side_stake = unit_size, o_side_stake = unit_size
|
|
888
|
+
if(higher_probability_order == 'trade'){
|
|
889
|
+
//If that is the stake, then the potential winnigns is
|
|
890
|
+
let pot_win = MarketMaketHelpers.calcPotentialWinnings(trade_side_stake, novig_trade_side_odds);
|
|
891
|
+
o_side_stake = MarketMaketHelpers.calcSaleValue(novig_o_side_odds, pot_win);
|
|
892
|
+
} else {
|
|
893
|
+
//If that is the stake, then the potential winnigns is
|
|
894
|
+
let pot_win = MarketMaketHelpers.calcPotentialWinnings(o_side_stake, novig_o_side_odds);
|
|
895
|
+
trade_side_stake = MarketMaketHelpers.calcSaleValue(novig_trade_side_odds, pot_win);
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
o_side_order = {
|
|
899
|
+
...o_side_order,
|
|
900
|
+
probability: no_vig_o_price,
|
|
901
|
+
odds: novig_o_side_odds,
|
|
902
|
+
fulfill_action: 'drain',
|
|
903
|
+
expire_datetime: expire_datetime,
|
|
904
|
+
potential_winnings: MarketMaketHelpers.calcPotentialWinnings(o_side_stake, novig_o_side_odds),
|
|
905
|
+
open_amt: o_side_stake,
|
|
906
|
+
}
|
|
907
|
+
trade_side_order = {
|
|
908
|
+
...trade_side_order,
|
|
909
|
+
probability: no_vig_trade_price,
|
|
910
|
+
odds: novig_trade_side_odds,
|
|
911
|
+
fulfill_action: 'drain',
|
|
912
|
+
expire_datetime: expire_datetime,
|
|
913
|
+
potential_winnings: MarketMaketHelpers.calcPotentialWinnings(trade_side_stake, novig_trade_side_odds),
|
|
914
|
+
open_amt: trade_side_stake,
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
return [ o_side_order, trade_side_order ]
|
|
918
|
+
}
|
|
756
919
|
}
|
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import { Button, Text, TextInput, View } from "../../Components/Themed"
|
|
3
|
+
import type { BestAvailableOrderProps, EventProps, ExternalPriceProps, LocationProps, MarketProps, MatchProps, OrderProps, TournamentProps, TradeProps } from '../../types';
|
|
4
|
+
import { MarketComponentApi, MarketComponentHelpers } from '../api';
|
|
5
|
+
import { ActivityIndicator, FlatList, type ViewStyle } from 'react-native';
|
|
6
|
+
import { Icons } from '../../Components';
|
|
7
|
+
import { useColors } from '../../constants/useColors';
|
|
8
|
+
import { MarketMaketHelpers } from '../../MarketMaker/api';
|
|
9
|
+
import OrderGradeBar from './OrderGradeBar';
|
|
10
|
+
import WeightProgress from './WeightProgress';
|
|
11
|
+
|
|
12
|
+
type CreateMarketFormProps = {
|
|
13
|
+
float?:boolean,
|
|
14
|
+
style?:ViewStyle
|
|
15
|
+
contest_type:'team'|'tournament'|'match',
|
|
16
|
+
contest_id:string,
|
|
17
|
+
best_available_orders:BestAvailableOrderProps[],
|
|
18
|
+
my_orders:OrderProps[],
|
|
19
|
+
action_loading?:boolean,
|
|
20
|
+
market_id:string,
|
|
21
|
+
unit_size?:number,
|
|
22
|
+
location?:LocationProps,
|
|
23
|
+
coordinates?:{ latitude:number, longitude:number, [key:string]:any }
|
|
24
|
+
side_type?:'side'|'team'|'athlete',
|
|
25
|
+
side_id?:string,
|
|
26
|
+
onCancel:() => void,
|
|
27
|
+
onSubmitOrders:(orders:OrderProps[]) => void
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
const sections = ['o_side', 'submit', 'trade_side', 'draft_orders','my_orders', 'what_if'];
|
|
32
|
+
const CreateMarketForm = ({ float, action_loading, unit_size, location, coordinates, style, my_orders, best_available_orders, contest_type, contest_id, market_id, side_id, side_type, onCancel, onSubmitOrders }:CreateMarketFormProps) => {
|
|
33
|
+
const Colors = useColors();
|
|
34
|
+
const [ draft_orders, setDraftOrders ] = useState<OrderProps[]>([]);
|
|
35
|
+
const [ draft_data, setDraftData ] = useState<{
|
|
36
|
+
stake:string,
|
|
37
|
+
o_side_margin:number,
|
|
38
|
+
trade_side_margin:number
|
|
39
|
+
}>({
|
|
40
|
+
stake:unit_size?.toFixed(2) ?? '10',
|
|
41
|
+
o_side_margin: 0.02,
|
|
42
|
+
trade_side_margin: 0.02
|
|
43
|
+
});
|
|
44
|
+
const { o_side_margin, trade_side_margin, stake } = draft_data;
|
|
45
|
+
const [ form_data, setFormData ] = useState<{
|
|
46
|
+
loading:boolean,
|
|
47
|
+
markets:MarketProps[],
|
|
48
|
+
prices:ExternalPriceProps[],
|
|
49
|
+
trades:TradeProps[],
|
|
50
|
+
event?:EventProps,
|
|
51
|
+
tournament?:TournamentProps,
|
|
52
|
+
match?:MatchProps
|
|
53
|
+
}>({
|
|
54
|
+
loading:false,
|
|
55
|
+
markets: [],
|
|
56
|
+
prices: [],
|
|
57
|
+
trades: []
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const { loading, markets, prices, event, tournament, match } = form_data;
|
|
61
|
+
|
|
62
|
+
const { contest_title } = MarketComponentHelpers.getContestDetails(contest_type, event, tournament, match);
|
|
63
|
+
const market = markets.find(mk => mk.market_id == market_id);
|
|
64
|
+
|
|
65
|
+
const orders = MarketComponentHelpers.setMarket(parseFloat(stake), contest_type, best_available_orders, prices, o_side_margin, trade_side_margin, market, event, tournament, match, undefined, undefined)
|
|
66
|
+
const no_vig_data = MarketMaketHelpers.getNoVigPrice(prices, market);
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
MarketComponentApi.setEnvironment();
|
|
71
|
+
getFormData();
|
|
72
|
+
},[]);
|
|
73
|
+
|
|
74
|
+
const getFormData = async() => {
|
|
75
|
+
setFormData({ ...form_data, loading:true })
|
|
76
|
+
const mks = await MarketComponentApi.getMarkets();
|
|
77
|
+
let ev:EventProps | undefined, tourn:TournamentProps | undefined, mtch:MatchProps|undefined
|
|
78
|
+
if(contest_type == 'team'){
|
|
79
|
+
let evs = await MarketComponentApi.getEventsByEventIds([contest_id]);
|
|
80
|
+
ev = evs[0]
|
|
81
|
+
}
|
|
82
|
+
if(contest_type == 'tournament'){
|
|
83
|
+
let tourns = await MarketComponentApi.getTournamentsByTournamentIds([contest_id]);
|
|
84
|
+
tourn = tourns[0]
|
|
85
|
+
}
|
|
86
|
+
if(contest_type == 'match'){
|
|
87
|
+
let mtchs = await MarketComponentApi.getMatchesByMatchIds([contest_id]);
|
|
88
|
+
mtch = mtchs[0]
|
|
89
|
+
if(mtch){
|
|
90
|
+
let mtch_tourns = await MarketComponentApi.getTournamentsByTournamentIds([mtch.tournament_id]);
|
|
91
|
+
tourn = mtch_tourns[0]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
let contest_prices = await MarketComponentApi.getExternalPrices(contest_type, contest_id, market_id);
|
|
95
|
+
//Get the correct prices
|
|
96
|
+
if(side_type){ contest_prices = contest_prices.filter(p => p.participant_type == side_type && p.participant_id == side_id) }
|
|
97
|
+
//First try to get consensus
|
|
98
|
+
contest_prices = contest_prices.filter(p => p.external_name == 'Consensus');
|
|
99
|
+
if(contest_prices.length == 0){
|
|
100
|
+
let available_books = [ ...new Set(contest_prices.map(p => p.external_name)) ]
|
|
101
|
+
contest_prices = contest_prices.filter(p => p.external_name == available_books[0]);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let contest_trades = await MarketComponentApi.getLatestTradesByEvents(contest_type, [contest_id]);
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
setFormData({
|
|
108
|
+
...form_data,
|
|
109
|
+
loading:false,
|
|
110
|
+
markets: mks,
|
|
111
|
+
match: mtch,
|
|
112
|
+
event: ev,
|
|
113
|
+
tournament: tourn,
|
|
114
|
+
prices: contest_prices,
|
|
115
|
+
trades: contest_trades
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const handleSubmitOrder = () => {
|
|
120
|
+
if(action_loading){ return }
|
|
121
|
+
if(draft_orders.length == 0){ return alert('Unable to submit!') }
|
|
122
|
+
if(!location){ return alert('Unable to create order without location') }
|
|
123
|
+
if(!location.legal_ind){ return alert('Unable to create order in this location') }
|
|
124
|
+
if(!coordinates?.latitude){ return alert('Need coordinates') }
|
|
125
|
+
let new_orders = draft_orders.map(o => {
|
|
126
|
+
o.region = location.label
|
|
127
|
+
o.location = coordinates
|
|
128
|
+
return o
|
|
129
|
+
});
|
|
130
|
+
onSubmitOrders(new_orders)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const handleUpdateMargin = (side:'other'|'trade', direction: 'increase'|'decrease') => {
|
|
134
|
+
let o_side = o_side_margin
|
|
135
|
+
let trade_side = trade_side_margin
|
|
136
|
+
if(side == 'other' && direction == 'increase'){ o_side += 0.001 }
|
|
137
|
+
if(side == 'other' && direction == 'decrease'){ o_side -= 0.001 }
|
|
138
|
+
|
|
139
|
+
if(side == 'trade' && direction == 'increase'){ trade_side += 0.001 }
|
|
140
|
+
if(side == 'trade' && direction == 'decrease'){ trade_side -= 0.001 }
|
|
141
|
+
let total_margin = o_side + trade_side
|
|
142
|
+
if(total_margin < 0.001){ return } //Cant go negative!!
|
|
143
|
+
setDraftData({ o_side_margin: o_side, trade_side_margin: trade_side, stake })
|
|
144
|
+
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const renderOrders = (data:{ item:OrderProps, index:number }) => {
|
|
148
|
+
return (
|
|
149
|
+
<View style={{ flexGrow:1 }}>
|
|
150
|
+
<View style={{ padding:10 }}>
|
|
151
|
+
<Text theme='h1' textAlign='center'>{data.item.title}</Text>
|
|
152
|
+
</View>
|
|
153
|
+
</View>
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const renderSections = (data:{item:string, index:number}) => {
|
|
158
|
+
switch(data.item){
|
|
159
|
+
case 'my_orders':
|
|
160
|
+
if(!market){ return <></> }
|
|
161
|
+
const hedges = MarketMaketHelpers.getHedgesFromPositions(my_orders, markets);
|
|
162
|
+
const hedge = hedges[0]
|
|
163
|
+
const o_side_stats = MarketMaketHelpers.getOrderStats(my_orders.filter(o => o.side != market.trade_side));
|
|
164
|
+
const t_side_stats = MarketMaketHelpers.getOrderStats(my_orders.filter(o => o.side == market.trade_side));
|
|
165
|
+
const stake_weight = MarketMaketHelpers.getWeight(o_side_stats.stake_potential_winnings, t_side_stats.stake_potential_winnings, market);
|
|
166
|
+
const at_risk = o_side_stats.stake_potential_winnings - t_side_stats.stake_potential_winnings
|
|
167
|
+
return (
|
|
168
|
+
<View type='footer' style={{ padding:10 }}>
|
|
169
|
+
<View transparent style={{ flexDirection:'row', alignItems:'center', padding:10 }}>
|
|
170
|
+
<View transparent style={{ flex:1 }}>
|
|
171
|
+
<Text theme='h1'>My Current Position</Text>
|
|
172
|
+
</View>
|
|
173
|
+
{hedge?
|
|
174
|
+
<View transparent>
|
|
175
|
+
{hedge.delayed_cash_draw ?
|
|
176
|
+
<Text theme='error' size={14}>-${hedge.delayed_cash_draw.toFixed(2)}</Text>
|
|
177
|
+
:
|
|
178
|
+
<Text theme='success' size={14}>${hedge.delayed_cash_no_draw.toFixed(2)}</Text>
|
|
179
|
+
}
|
|
180
|
+
<Text theme='description'>Hedged</Text>
|
|
181
|
+
</View>
|
|
182
|
+
:<></>}
|
|
183
|
+
</View>
|
|
184
|
+
<View transparent type='row'>
|
|
185
|
+
<View transparent style={{ flex:1, padding:5 }}>
|
|
186
|
+
<Text theme='h2' textAlign='center'>{o_side_stats.stake_potential_winnings.toFixed(2)}</Text>
|
|
187
|
+
</View>
|
|
188
|
+
<View transparent style={{ flex:1, padding:5 }}>
|
|
189
|
+
<Text theme='h2' textAlign='center'>{t_side_stats.stake_potential_winnings.toFixed(2)}</Text>
|
|
190
|
+
</View>
|
|
191
|
+
</View>
|
|
192
|
+
<WeightProgress
|
|
193
|
+
style={{ margin:10 }}
|
|
194
|
+
min_value={0}
|
|
195
|
+
max_value={100}
|
|
196
|
+
value={stake_weight.weighted_pct}
|
|
197
|
+
bar_height={18}
|
|
198
|
+
/>
|
|
199
|
+
<View transparent type='row'>
|
|
200
|
+
{at_risk > 0 ?
|
|
201
|
+
<View transparent style={{ flex:1, padding:5 }}>
|
|
202
|
+
<Text theme='error' textAlign='center' style={{ marginTop:3 }}>${at_risk.toFixed(2)}</Text>
|
|
203
|
+
<Text theme='description' textAlign='center' style={{ marginTop:3 }}>At Risk</Text>
|
|
204
|
+
</View>
|
|
205
|
+
:<View style={{ flex:1 }} />}
|
|
206
|
+
{at_risk < 0 ?
|
|
207
|
+
<View transparent style={{ flex:1, padding:5 }}>
|
|
208
|
+
<Text theme='error' textAlign='center' style={{ marginTop:3 }}>${at_risk.toFixed(2)}</Text>
|
|
209
|
+
<Text theme='description' textAlign='center' style={{ marginTop:3 }}>At Risk</Text>
|
|
210
|
+
</View>
|
|
211
|
+
:<View style={{ flex:1 }} />}
|
|
212
|
+
</View>
|
|
213
|
+
</View>
|
|
214
|
+
)
|
|
215
|
+
case 'o_side':
|
|
216
|
+
if(draft_orders.length > 0){ return <></> }
|
|
217
|
+
if(!market){ return <></> }
|
|
218
|
+
let o_side_option = market.side_options.find(so => so.side != market.trade_side);
|
|
219
|
+
if(!o_side_option){ return <></> }
|
|
220
|
+
const o_side_order = orders.find(o => o.side != market.trade_side);
|
|
221
|
+
if(!o_side_order){ return <></> }
|
|
222
|
+
const o_side_price = prices.find(p => p.side != market.trade_side);
|
|
223
|
+
const o_side_no_vig = no_vig_data?.o_side_odds
|
|
224
|
+
const o_best_available = best_available_orders.find(o => o.market_id == market_id && o.side != market.trade_side)
|
|
225
|
+
//const my_o_side_open = my_orders.filter(o => o.market_id == market_id && o.side != market.trade_side);
|
|
226
|
+
//const my_open_stats = MarketMaketHelpers.getOrderStats(my_o_side_open, o_best_available);
|
|
227
|
+
return (
|
|
228
|
+
<View style={{ borderWidth:1, borderColor:Colors.borders.light, margin:10 }}>
|
|
229
|
+
<View type='row' style={{ padding:10, borderBottomWidth:1, borderColor:Colors.borders.light }}>
|
|
230
|
+
<View transparent style={{ flex:1 }}>
|
|
231
|
+
<Text theme='h2'>{o_side_order.title}</Text>
|
|
232
|
+
<Text theme='description' style={{ marginTop:3 }}>${o_side_order.open_amt.toFixed(2)} to win ${o_side_order.potential_winnings.toFixed(2)}</Text>
|
|
233
|
+
</View>
|
|
234
|
+
<Text theme='h1'>${o_side_order.open_amt.toFixed(2)}</Text>
|
|
235
|
+
<View type='row' style={{ marginLeft:10 }}>
|
|
236
|
+
<Button float onPress={() => handleUpdateMargin('other', 'increase')}>
|
|
237
|
+
<Icons.ChevronIcon direction='left' size={8} color={Colors.text.h1} />
|
|
238
|
+
</Button>
|
|
239
|
+
<View style={{ paddingLeft:10, paddingRight:10 }}>
|
|
240
|
+
<Text theme='h1' textAlign='center'>{(o_side_order.probability * 100).toFixed(2)}%</Text>
|
|
241
|
+
<Text theme='light' style={{ marginTop:3 }} textAlign='center'>{MarketComponentHelpers.getOddsLabel(o_side_order.odds)}</Text>
|
|
242
|
+
</View>
|
|
243
|
+
<Button float onPress={() => handleUpdateMargin('other', 'decrease')}>
|
|
244
|
+
<Icons.ChevronIcon direction='right' size={8} color={Colors.text.h1} />
|
|
245
|
+
</Button>
|
|
246
|
+
</View>
|
|
247
|
+
</View>
|
|
248
|
+
{o_best_available ?
|
|
249
|
+
<View type='row' style={{ padding:10 }}>
|
|
250
|
+
<View transparent style={{flex:1}}>
|
|
251
|
+
<Text theme='h1'>{o_best_available.title}</Text>
|
|
252
|
+
{o_best_available.grade ?
|
|
253
|
+
<OrderGradeBar style={{ alignSelf:'flex-start', marginTop:3 }} grade={o_best_available.grade} view_type='card' onSelectGrade={() => console.log('')}/>
|
|
254
|
+
:<></>}
|
|
255
|
+
</View>
|
|
256
|
+
<View style={{ alignItems:'flex-end' }}>
|
|
257
|
+
<Text theme='h2'>{MarketComponentHelpers.getOddsLabel(o_best_available.odds)}</Text>
|
|
258
|
+
<Text theme='success'>${o_best_available.open_amt.toFixed(2)} Available</Text>
|
|
259
|
+
</View>
|
|
260
|
+
<Button
|
|
261
|
+
title='BUY'
|
|
262
|
+
type='success'
|
|
263
|
+
loading={action_loading}
|
|
264
|
+
style={{ padding:10, marginLeft:10, opacity: action_loading ? 0.5:1 }}
|
|
265
|
+
disabled={action_loading}
|
|
266
|
+
onPress={() => {
|
|
267
|
+
let side_ids = MarketComponentHelpers.getSideIds(contest_type, o_side_option, market, event, tournament, match, undefined, undefined);
|
|
268
|
+
if(!side_ids){ return }
|
|
269
|
+
let trade = MarketMaketHelpers.getTradeFromAvailableOrder(o_best_available, side_ids.reversed_side_id);
|
|
270
|
+
let order = MarketMaketHelpers.getOrderFromTrade(trade, unit_size ?? 10, o_best_available.order_id);
|
|
271
|
+
order.title = o_best_available.title
|
|
272
|
+
setDraftOrders([order])
|
|
273
|
+
}}
|
|
274
|
+
/>
|
|
275
|
+
</View>
|
|
276
|
+
:<></>}
|
|
277
|
+
{o_side_price && o_side_no_vig ?
|
|
278
|
+
<View type='footer' style={{ flexDirection:'row', alignItems:'center', padding:10 }}>
|
|
279
|
+
<View transparent style={{ flex:1 }}>
|
|
280
|
+
<Text theme='h1'>{o_side_price.external_name}</Text>
|
|
281
|
+
<Text theme='light' style={{ marginTop:3 }}>External price with vig removed</Text>
|
|
282
|
+
</View>
|
|
283
|
+
<Text theme='h2'>{MarketComponentHelpers.getOddsLabel(o_side_no_vig)}</Text>
|
|
284
|
+
</View>
|
|
285
|
+
:<></>}
|
|
286
|
+
</View>
|
|
287
|
+
|
|
288
|
+
)
|
|
289
|
+
case 'submit':
|
|
290
|
+
if(draft_orders.length > 0){ return <></> }
|
|
291
|
+
return (
|
|
292
|
+
<View type='header' style={{ flexDirection:'row', padding:10 }}>
|
|
293
|
+
<TextInput
|
|
294
|
+
value={stake}
|
|
295
|
+
style={{ width:100, textAlign:'center' }}
|
|
296
|
+
onChangeText={(text) => setDraftData({ ...draft_data, stake:text })}
|
|
297
|
+
/>
|
|
298
|
+
<Button
|
|
299
|
+
style={{ flex:2, marginLeft:10, opacity: action_loading?0.5:1 }}
|
|
300
|
+
type='success'
|
|
301
|
+
loading={action_loading}
|
|
302
|
+
disabled={action_loading}
|
|
303
|
+
title='SET MARKET'
|
|
304
|
+
onPress={() => setDraftOrders(orders)}
|
|
305
|
+
/>
|
|
306
|
+
</View>
|
|
307
|
+
)
|
|
308
|
+
case 'trade_side':
|
|
309
|
+
if(draft_orders.length > 0){ return <></> }
|
|
310
|
+
if(!market){ return <></> }
|
|
311
|
+
let trade_side_option = market.side_options.find(so => so.side == market.trade_side);
|
|
312
|
+
if(!trade_side_option){ return <></> }
|
|
313
|
+
const trade_side_order = orders.find(o => o.side == market.trade_side);
|
|
314
|
+
if(!trade_side_order){ return <></> }
|
|
315
|
+
const trade_side_price = prices.find(p => p.side == market.trade_side);
|
|
316
|
+
const trade_side_no_vig_odds = no_vig_data?.trade_side_odds
|
|
317
|
+
const t_best_available = best_available_orders.find(o => o.market_id == market_id && o.side == market.trade_side)
|
|
318
|
+
return (
|
|
319
|
+
<View style={{ borderWidth:1, borderColor:Colors.borders.light, margin:10 }}>
|
|
320
|
+
<View type='row' style={{ padding:10 }}>
|
|
321
|
+
<View transparent style={{ flex:1 }}>
|
|
322
|
+
<Text theme='h2'>{trade_side_order.title}</Text>
|
|
323
|
+
<Text theme='description' style={{ marginTop:3 }}>${trade_side_order.open_amt.toFixed(2)} to win ${trade_side_order.potential_winnings.toFixed(2)}</Text>
|
|
324
|
+
</View>
|
|
325
|
+
<Text theme='h1'>${trade_side_order.open_amt.toFixed(2)}</Text>
|
|
326
|
+
<View type='row' style={{ marginLeft:10 }}>
|
|
327
|
+
<Button float onPress={() => handleUpdateMargin('trade', 'increase')}>
|
|
328
|
+
<Icons.ChevronIcon direction='left' size={8} color={Colors.text.h1} />
|
|
329
|
+
</Button>
|
|
330
|
+
<View style={{ paddingLeft:10, paddingRight:10 }}>
|
|
331
|
+
<Text theme='h1'>{(trade_side_order.probability * 100).toFixed(2)}%</Text>
|
|
332
|
+
<Text theme='light' style={{ marginTop:3 }} textAlign='center'>{MarketComponentHelpers.getOddsLabel(trade_side_order.odds)}</Text>
|
|
333
|
+
</View>
|
|
334
|
+
<Button float onPress={() => handleUpdateMargin('trade', 'decrease')}>
|
|
335
|
+
<Icons.ChevronIcon direction='right' size={8} color={Colors.text.h1} />
|
|
336
|
+
</Button>
|
|
337
|
+
</View>
|
|
338
|
+
</View>
|
|
339
|
+
{t_best_available ?
|
|
340
|
+
<View type='row' style={{ padding:10 }}>
|
|
341
|
+
<View transparent style={{flex:1}}>
|
|
342
|
+
<Text theme='h1'>{t_best_available.title}</Text>
|
|
343
|
+
{t_best_available.grade ?
|
|
344
|
+
<OrderGradeBar style={{ alignSelf:'flex-start', marginTop:3 }} grade={t_best_available.grade} view_type='card' onSelectGrade={() => console.log('')}/>
|
|
345
|
+
:<></>}
|
|
346
|
+
</View>
|
|
347
|
+
<View style={{ alignItems:'flex-end' }}>
|
|
348
|
+
<Text theme='h2'>{MarketComponentHelpers.getOddsLabel(t_best_available.odds)}</Text>
|
|
349
|
+
<Text theme='success'>${t_best_available.open_amt.toFixed(2)} Available</Text>
|
|
350
|
+
</View>
|
|
351
|
+
<Button
|
|
352
|
+
title='BUY'
|
|
353
|
+
type='success'
|
|
354
|
+
style={{ padding:10, marginLeft:10, opacity: action_loading ? 0.5:1 }}
|
|
355
|
+
disabled={action_loading}
|
|
356
|
+
onPress={() => {
|
|
357
|
+
let side_ids = MarketComponentHelpers.getSideIds(contest_type, trade_side_option, market, event, tournament, match, undefined, undefined);
|
|
358
|
+
if(!side_ids){ return }
|
|
359
|
+
let trade = MarketMaketHelpers.getTradeFromAvailableOrder(t_best_available, side_ids.reversed_side_id);
|
|
360
|
+
let order = MarketMaketHelpers.getOrderFromTrade(trade, unit_size ?? 10, t_best_available.order_id);
|
|
361
|
+
order.title = t_best_available.title
|
|
362
|
+
setDraftOrders([order])
|
|
363
|
+
}}
|
|
364
|
+
/>
|
|
365
|
+
</View>
|
|
366
|
+
:<></>}
|
|
367
|
+
{trade_side_price && trade_side_no_vig_odds ?
|
|
368
|
+
<View type='footer' style={{ flexDirection:'row', alignItems:'center', padding:10 }}>
|
|
369
|
+
<View transparent style={{ flex:1 }}>
|
|
370
|
+
<Text theme='h1'>{trade_side_price.external_name}</Text>
|
|
371
|
+
<Text theme='light' style={{ marginTop:3 }}>External price with vig removed</Text>
|
|
372
|
+
</View>
|
|
373
|
+
<Text theme='h2'>{MarketComponentHelpers.getOddsLabel(trade_side_no_vig_odds)}</Text>
|
|
374
|
+
</View>
|
|
375
|
+
:<></>}
|
|
376
|
+
</View>
|
|
377
|
+
)
|
|
378
|
+
case 'draft_orders':
|
|
379
|
+
if(draft_orders.length == 0){ return <></> }
|
|
380
|
+
return (
|
|
381
|
+
<View style={{ flexDirection:'row', flexWrap:'wrap' }}>
|
|
382
|
+
{draft_orders.map((o,i) => {
|
|
383
|
+
return renderOrders({ item: o, index:i })
|
|
384
|
+
})}
|
|
385
|
+
</View>
|
|
386
|
+
)
|
|
387
|
+
case 'what_if':return <></>
|
|
388
|
+
default: return <></>
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const total_margin = o_side_margin + trade_side_margin
|
|
393
|
+
return (
|
|
394
|
+
<View float={float} style={{ ...style }}>
|
|
395
|
+
<View type='header' style={{ flexDirection:'row', alignItems:'center', padding:10, borderTopLeftRadius:8, borderTopRightRadius:8 }}>
|
|
396
|
+
<View transparent style={{ flex:1 }}>
|
|
397
|
+
<Text theme='h1'>{contest_title}</Text>
|
|
398
|
+
</View>
|
|
399
|
+
<View transparent style={{ justifyContent:'center', alignItems:'center' }}>
|
|
400
|
+
<Text theme='h2' color={total_margin > 0.06 ? Colors.text.error : total_margin > 0.045 ? Colors.text.warning : Colors.text.success}>{(total_margin*100).toFixed(2)}%</Text>
|
|
401
|
+
<Text theme='description' textAlign='center'>Margin</Text>
|
|
402
|
+
</View>
|
|
403
|
+
</View>
|
|
404
|
+
<View type='body' style={{ flex:1 }}>
|
|
405
|
+
{loading ?
|
|
406
|
+
<ActivityIndicator size='large' color={Colors.text.h1} />
|
|
407
|
+
:<></>}
|
|
408
|
+
<FlatList
|
|
409
|
+
key={'create_market_sections'}
|
|
410
|
+
keyExtractor={item => item}
|
|
411
|
+
renderItem={renderSections}
|
|
412
|
+
data={sections}
|
|
413
|
+
/>
|
|
414
|
+
</View>
|
|
415
|
+
{draft_orders.length == 0 ?
|
|
416
|
+
<View type='footer' style={{ flexDirection:'row', alignItems:'center', padding:10, borderBottomRightRadius:8, borderBottomLeftRadius:8 }}>
|
|
417
|
+
<Button
|
|
418
|
+
style={{ flex:1 }}
|
|
419
|
+
type='action'
|
|
420
|
+
title='CLOSE'
|
|
421
|
+
onPress={() => onCancel()}
|
|
422
|
+
/>
|
|
423
|
+
</View>
|
|
424
|
+
:
|
|
425
|
+
<View type='footer' style={{ flexDirection:'row', alignItems:'center', padding:10, borderBottomRightRadius:8, borderBottomLeftRadius:8 }}>
|
|
426
|
+
<Button
|
|
427
|
+
style={{ flex:1 }}
|
|
428
|
+
type='error'
|
|
429
|
+
title='CANCEL'
|
|
430
|
+
onPress={() => setDraftOrders([])}
|
|
431
|
+
/>
|
|
432
|
+
<Button
|
|
433
|
+
style={{ flex:2, marginLeft:5 }}
|
|
434
|
+
type='success'
|
|
435
|
+
title='SUBMIT ORDERS'
|
|
436
|
+
onPress={() => handleSubmitOrder()}
|
|
437
|
+
/>
|
|
438
|
+
</View>
|
|
439
|
+
}
|
|
440
|
+
</View>
|
|
441
|
+
)
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
export default CreateMarketForm
|