X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~yarrgweb/git?a=blobdiff_plain;f=yarrg%2Fweb%2Froutetrade;h=9a6824e97ced58bb08b3e84b11e43f975fe8505f;hb=099cd920655c1db6da4a1a57ec3baa30d16321d7;hp=eadc473d4b23dac47885d569b89a79d12a741ae5;hpb=880b063ca880504e85bbeba2e37fc8faa187947e;p=ypp-sc-tools.db-live.git diff --git a/yarrg/web/routetrade b/yarrg/web/routetrade index eadc473..9a6824e 100644 --- a/yarrg/web/routetrade +++ b/yarrg/web/routetrade @@ -32,30 +32,30 @@ This Mason component is the core trade planner for a specific route. -========== TODO ========== -16:36 alpha,byrne,papaya,turtle,jorvik,luthien is my example - -use POST for update. Hrrm. - -LATER OR NOT AT ALL - -adjustable potential cost of losses (rather than fixed 1e-BIG per league) - -max volume/mass - -========== TODO ========== - <%args> $dbh @islandids @archipelagoes $qa +$max_mass +$max_volume +$lossperleaguepct <&| script &> da_pageload= Date.now(); +% if (defined $max_mass || defined $max_volume) { +WARNING - VESSEL CAPACITY LIMIT NOT YET IMPLEMENTED +

+% } +% if (defined $lossperleaguepct) { +WARNING - DEFINED LOSS PER LEAGUE NOT YET IMPLEMENTED +<% $lossperleaguepct |h %> +

+% } + <%perl> my $now= time; @@ -63,6 +63,7 @@ my $loss_per_league= 1e-7; my @flow_conds; my @query_params; +my %dists; my $sd_condition= sub { my ($bs, $ix) = @_; @@ -98,10 +99,12 @@ foreach my $src_i (0..$#islandids) { if ($specific && !$confusing && # With a circular route, do not carry goods round the loop - !($src_i==0 && $dst_i==$#islandids && + !(($src_i==0 || $src_i==$#islandids) && + $dst_i==$#islandids && $src_isle == $islandids[$dst_i])) { if ($islandpair{$src_isle,$dst_isle}) { $confusing= 1; +print "confusing $src_i $src_isle $dst_i $dst_isle\n"; } else { $islandpair{$src_isle,$dst_isle}= [ $src_i, $dst_i ]; @@ -172,6 +175,20 @@ my $sth= $dbh->prepare($stmt); $sth->execute(@query_params); my @flows; +my $distquery= $dbh->prepare(" + SELECT dist FROM dists WHERE aiid = ? AND biid = ? + "); +my $distance= sub { + my ($from,$to)= @_; + my $d= $dists{$from}{$to}; + return $d if defined $d; + $distquery->execute($from,$to); + $d = $distquery->fetchrow_array(); + defined $d or die "$from $to ?"; + $dists{$from}{$to}= $d; + return $d; +}; + my @cols= ({ NoSort => 1 }); my $addcols= sub { @@ -201,9 +218,12 @@ $addcols->({ DoReverse => 1, SortColKey => 'MarginSortKey' }, qw( Margin )); $addcols->({ DoReverse => 1 }, - qw( unitprofit MaxQty - MaxCapital MaxProfit + qw( unitprofit MaxQty MaxCapital MaxProfit dist )); +foreach my $v (qw(MaxMass MaxVolume)) { + $addcols->({ + DoReverse => 1, Total => 0, SortColKey => "${v}SortKey" }, $v); +} @@ -252,6 +272,12 @@ $addcols->({ DoReverse => 1 }, % } <%perl> + +if (!@flows) { + print 'No profitable trading opportunities were found.'; + return; +} + foreach my $f (@flows) { $f->{MaxQty}= $f->{'org_qty_agg'} < $f->{'dst_qty_agg'} @@ -259,6 +285,12 @@ foreach my $f (@flows) { $f->{MaxProfit}= $f->{MaxQty} * $f->{'unitprofit'}; $f->{MaxCapital}= $f->{MaxQty} * $f->{'org_price'}; + $f->{MaxMassSortKey}= $f->{MaxQty} * $f->{'unitmass'}; + $f->{MaxVolumeSortKey}= $f->{MaxQty} * $f->{'unitvolume'}; + foreach my $v (qw(Mass Volume)) { + $f->{"Max$v"}= sprintf "%.1f", $f->{"Max${v}SortKey"} * 1e-6; + } + $f->{MarginSortKey}= sprintf "%d", $f->{'dst_price'} * 10000 / $f->{'org_price'}; $f->{Margin}= sprintf "%3.1f%%", @@ -268,6 +300,8 @@ foreach my $f (@flows) { $f->{'dst_price'} * (1.0 - $loss_per_league) ** $f->{'dist'} - $f->{'org_price'}; + $dists{'org_id'}{'dst_id'}= $f->{'dist'}; + my @uid= $f->{commodid}; foreach my $od (qw(org dst)) { push @uid, @@ -353,7 +387,7 @@ Route contains archipelago(es), not just specific islands. Route is complex - it visits the same island several times and isn't a simple loop. % } -Therefore, optimal trade pattern not calculated. +Therefore, optimal voyage trade plan not calculated. % } else { # ========== OPTMISATION ========== <%perl> @@ -423,7 +457,9 @@ if ($qa->{'debug'}) { qw(glpsol --cpxlp /dev/stdin -o /dev/stdout)); print "

\n" if $qa->{'debug'};
 	my $found_section= 0;
+	my $glpsol_out= '';
 	while (<$output>) {
+		$glpsol_out.= $_;
 		print encode_entities($_) if $qa->{'debug'};
 		if (m/^\s*No\.\s+Column name\s+St\s+Activity\s/) {
 			die if $found_section>0;
@@ -444,8 +480,9 @@ if ($qa->{'debug'}) {
 		$flow->{OptCapital}= $flow->{OptQty} * $flow->{'org_price'};
 	}
 	print "
\n" if $qa->{'debug'}; - pipethrough_run_finish($output, 'glpsol'); - die unless $found_section; + my $prerr= "\n=====\n$cplex\n=====\n$glpsol_out\n=====\n "; + pipethrough_run_finish($output,$prerr); + die $prerr unless $found_section; }; $addcols->({ DoReverse => 1 }, qw( @@ -472,6 +509,7 @@ $addcols->({ Total => 0, DoReverse => 1 }, qw( + % if ($optimise) { % } @@ -484,6 +522,8 @@ $addcols->({ Total => 0, DoReverse => 1 }, qw( Deliver Profit Max + +Max % if ($optimise) { Planned % } @@ -502,6 +542,9 @@ $addcols->({ Total => 0, DoReverse => 1 }, qw( Qty Capital Profit +Dist +Mass +Vol % if ($optimise) { Qty Capital @@ -524,7 +567,8 @@ $addcols->({ Total => 0, DoReverse => 1 }, qw( % foreach my $ci (1..$#cols) { % my $col= $cols[$ci]; % my $v= $flow->{$col->{Name}}; -% $col->{Total} += $v if defined $col->{Total}; +% $col->{Total} += $v +% if defined $col->{Total} and not $flow->{Suppress}; % $v='' if !$col->{Text} && !$v; % my $sortkey= $col->{SortColKey} ? % $flow->{$col->{SortColKey}} : $v; @@ -544,15 +588,10 @@ $addcols->({ Total => 0, DoReverse => 1 }, qw( % } -<& tabsort, cols => \@cols, table => 'trades', rowclass => 'datarow', +<&| tabsort, cols => \@cols, table => 'trades', rowclass => 'datarow', throw => 'trades_sort', tbrow => 'trades_total' &> -<&| script &> ts_sortkeys= <% to_json_protecttags(\%ts_sortkeys) %>; - function all_onload() { - ts_onload__trades(); - } - window.onload= all_onload; - + @@ -561,20 +600,24 @@ $addcols->({ Total => 0, DoReverse => 1 }, qw( % my $iquery= $dbh->prepare('SELECT islandname FROM islands % WHERE islandid = ?'); % my %da_ages; +% my $total_total= 0; +% my $total_dist= 0; %

Voyage trading plan

% foreach my $i (0..$#islandids) { - % } - <%perl> my $age_reported= 0; my %flowlists; @@ -583,6 +626,11 @@ Sail to <% $islandname |h %> next if $f->{Suppress}; next unless $f->{"${od}_id"} == $islandids[$i]; next unless $f->{OptQty}; + my $arbitrage= $f->{'org_id'} == $f->{'dst_id'}; + my $loop= $islandids[0] == $islandids[-1] && + ($i==0 || $i==$#islandids); + next if $loop and ($arbitrage ? $i : + !!$i == !!($od eq 'org')); my $price= $f->{"${od}_price"}; my $stallname= $f->{"${od}_stallname"}; my $todo= \$flowlists{$od}{ @@ -603,9 +651,7 @@ Sail to <% $islandname |h %> $$todo->{Qty} += $f->{OptQty}; $$todo->{Total}= $$todo->{Price} * $$todo->{Qty}; $$todo->{Stalls}= $f->{"${od}Stalls"}; - if ($f->{'org_id'} == $f->{'dst_id'}) { - $$todo->{"${od}Arbitrage"}= 1; - } + $$todo->{"${od}Arbitrage"}= 1 if $arbitrage; } } @@ -657,25 +703,32 @@ Sail to <% $islandname |h %> % } % }; % my $show_total= sub { -% my ($totaldesc)= @_; +% my ($totaldesc, $sign)= @_; % if (defined $total) { +
+
% $iquery->execute($islandids[$i]); % my ($islandname) = $iquery->fetchrow_array(); % if (!$i) { -Start at <% $islandname |h %> +Start at <% $islandname |h %> % } else { -Sail to <% $islandname |h %> +% my $this_dist= $distance->($islandids[$i-1],$islandids[$i]); +% $total_dist += $this_dist; +Sail to <% $islandname |h %> +- <% $this_dist |h %> leagues
<% $totaldesc %> <% $total |h %> total +% $total_total += $sign * $total; % } % $total= undef; % $dline= 0; <%perl> }; - $show_flows->('dst',0,'Deliver'); $show_total->('Proceeds'); - $show_flows->('org',1,'Collect'); $show_total->('(Arbitrage) outlay'); - $show_flows->('dst',1,'Deliver'); $show_total->('(Arbitrage) proceeds'); - $show_flows->('org',0,'Collect'); $show_total->('Outlay'); + $show_flows->('dst',0,'Deliver'); $show_total->('Proceeds',1); + $show_flows->('org',1,'Collect'); $show_total->('(Arbitrage) outlay',-1); + $show_flows->('dst',1,'Deliver'); $show_total->('(Arbitrage) proceeds',1); + $show_flows->('org',0,'Collect'); $show_total->('Outlay',-1); } +
Total distance: <% $total_dist %> leagues. +Overall net cash flow +<% + $total_total < 0 ? -$total_total." loss" : $total_total." gain" + %>
<& query_age:dataages, id2age => \%da_ages &> %