In-Development TradeDangerous: power-user trade optimizer

I think it would be useful to have a list of commands and what they do..
Im trying to piece things together but I keep seeing commands that I had no clue about previously. For example, CTRL-C, this closes the program? Previously I thought just closing the cmd window would close out the program.

thanks ;)

Run trade.py with "--help"; for details on what a given command does, type "trade.py commandname" --help, e.g. "trade.py cleanup --help".
 
Yes. That's an idiotic Python issue. The "pip" script is generally at
Code:
C:\Python34\Scripts\pip.exe

You'll need to fully specify the path to run pip, or go inside the Scripts directory and run pip from there.

Think this depends on whether you allowed Python to add itself to the system PATH during installation and/or whether you made it available for all users.

If you chose not to do those things, then you won't have access to "pip" from the command line without doing what Rikkles describes.
 
emdn-tap.py -v --commit 30 --warn 2>warnings.txt

Whats is this doing??

I can run this command alone and it starts telling me that it is committing records.

ED is not even running.
Where is the data coming from and going to?

Per the README.txt, it's connecting to the "Elite Market Data Network" - an ED fan created system that lets people capture prices while playing and sharing them with other people. It's a real-time ticker, you can't query it for past prices, you can only see current prices.

The "sharing" part is called "the firehose" and "emdn-tap" is a script I've written for TD that drinks from that firehose and stores the data. The alternative is that you hand-edit a ".prices" file as you visit stations and populate your own local database with prices you've seen.

EMDN:
Pros: Data from stations you probably won't visit; data tends to be relatively fresh;
Cons: Data can be inaccurate or faked by jerks,

Hand Edit:
Pros: For me, gives more of a connection with the market; you generally know the data is accurate;
Cons: Time consuming; data gets stale unless you revisit stations; falls afoul of the same UI issue that tricks EMDN into thinking quest items you have in your cargo are sold at stations that don't sell it.

Elite Dangerous/Frontier don't currently provide an official way to get market data from outside the game.

Also..
Im not sure how to use it..

Well, again, "emdn-tap.py --help".

Per the front post and the readme, if you want to know more about EMDN see Andreas' post: http://forums.frontier.co.uk/showthread.php?t=23585
 
Excellent..
So, basically I can open up my cmd prompt..
run emdn-tap
Open another cmd prompt for my trade.py calculations

Run cleanup once in awhile.

And be all good.. correct??


Also..am I correct in saying that I do Not need to run Andreas EMDN and firehose for this to work??
 
Speaking about roundtrips. Given the amazing speed of TD. Would it be possible to find the best roundtrips, not for two but for for example 3-4 stations. So it involves buying/selling at multiple stations to get the best trade route.

So I think you're missing what TD actually is. BPC does a good job of recommending a profitable trade A->B and A->B->A.

That doesn't mean it's telling you the best profit you can make, because it doesn't take into account how much money you made A->B.

TD actually works out the best possible cargo fit for your capacity and credit limit, and sometimes, when you're low on credits, it will find peculiar cases where it is more profitable to buy less of the most profitable thing you can afford and take a bunch of extra cheapo items, e.g. instead of buying 13 Agri-medicines, just buy 12 and take the 7 units of biowaste you can currently afford. Neither will fill your cargo hold but you'll make more profit from the second option.

Imagine you've got 8 cargo space and 1000 credits. There's an item, X, that costs 250cr that makes 100cr profit each, and an item, Y, that costs 50cr that makes 30 profit each.

A full load of X would make you 800cr but you can only afford 4 which would make you 100cr. You can afford a full load, 8, of Y which would make you 120cr.

Alternative load outs:

Code:
XYYYYYYY : costs 250 + 350 => 600cr, profit = 100 + 210 => 310cr
XXYYYYYY : costs 500 + 300 => 800cr, profit = 200 + 180 => 380cr
XXXYYYYY : costs 750 + 250 => 1000cr, profit = 300 + 150 => 450cr
XXXX---- : costs 1000 + 0 => 1000cr, profit = 400 + 0 => 400cr
YYYYYYYY : costs 0 + 400 => 400cr, profit = 0 + 120 => 120cr

Guess which TD will pick? (And we'll see this in my example run shortly)

This brings us to the whole reason I started TD: Round trips aren't always the best way to make money.

TD takes into account the money you should make from each [potential] hop (it assumes a margin of error which you can control with --margin), and it continues projecting all of the runner up choices as it goes.

A round trip is no guarantee of profitability. If A->B offers 500cr/unit and B->A offers 300cr/unit, you're averaging 400cr/unit over your run. You could be missing out on a sweet deal B->C.

TD evaluates routes based on the overall profitability, so sometimes round trips will show up in it, but that's not because it looks for them. It just finds the best way to make money with what you have for the number of hops you can afford to make.

Consider this example: Guy just bought a cobra and left himself 100 credits. What can he do in just 8 hops?

Code:
$ ./trade.py run --ship cobra --from chango --cr 100 --hops 8
I BOOTIS/Chango Dock -> BD+47 2112/Olivas Settlement:
 >-> At I BOOTIS/Chango Dock, Buy: 6 x Algae,
  +  At RAKAPILA/Stone Enterprise, Buy: 32 x Biowaste,
  +  At I BOOTIS/Chango Dock, Buy: 36 x Food Cartridges,
  +  At RAKAPILA/Stone Enterprise, Buy: 36 x Clothing,
  +  At AULIN/Aulin Enterprise, Buy: 12 x Agri-Medicines, 7 x Biowaste,
  +  At WYRD/Vonarburg Co-operative, Buy: 36 x Fish,
  +  At AULIN/Aulin Enterprise, Buy: 30 x Agri-Medicines, 2 x Pesticides, 3 x Biowaste,
  +  At WYRD/Vonarburg Co-operative, Buy: 36 x Fish,
 <-< Olivas Settlement gaining 43,394cr => 43,494cr total

First - note that TD is suggesting multiple items to fill up the hold; it's not just telling you the most profitable item, it's figuring out what you can afford, what you can fit, and what, when combined, will make the absolute maximum profit - down to the credit.

And second note that after the second jump to Rakapila TD changes route. Why? Because it knows that at that point you've made enough money to be able to buy something much more profitable that algae and biowaste.

Lets ask TD to show us more of what its thinking (-v -v -v or -vvv)

Code:
$ ./trade.py run --ship cobra --from chango --cr 100 --hops 8 -v -v -v
With 100cr / From I BOOTIS/Chango Dock / To Anywhere
36 cap, 8 hops, max 2 jumps/hop and max 7.30 ly/jump

I BOOTIS/Chango Dock -> BD+47 2112/Olivas Settlement:
Start CR:        100
Hops    :          8
Jumps   :         14
Gain CR :     43,394
Gain/Hop:      5,424
Final CR:     43,494

 >-> At I BOOTIS/Chango Dock, Buy:
  |      6 x Algae                          @         15cr each,         90cr total,
  |   100cr => i Bootis -> Aulin -> Rakapila => Gain 480cr (80cr/ton) => 580cr

This first hop we couldn't afford much, but it can make us 480 credits with Algae.
Code:
  +  At RAKAPILA/Stone Enterprise, Buy:
  |     32 x Biowaste                       @         18cr each,        576cr total,
  |   580cr => Rakapila -> Aulin -> i Bootis => Gain 1,568cr (49cr/ton) => 2,148cr

It's figured out here that we can afford 32 biowaste with the extra profit we've made. If it didn't, it would instead tell us to buy 5 units of Biowaste and probably sell it somewhere else. Back to our route:

Code:
  +  At I BOOTIS/Chango Dock, Buy:
  |     36 x Food Cartridges                @         19cr each,        684cr total,
  |   2,148cr => i Bootis -> Aulin -> Rakapila => Gain 2,988cr (83cr/ton) => 5,136cr

It found a much better trade at chango when we started with 2100 credits this time, and we're going to make much more money selling the load.

The calculator component is actually more cautious than these values suggest, so we may actually be able to afford something more expensive. Try the same route with "--margin 0" and "--margin 0.25".

But we're still going back to Rakapila.

Code:
  +  At RAKAPILA/Stone Enterprise, Buy:
  |     36 x Clothing                       @        129cr each,      4,644cr total,
  |   5,136cr => Rakapila -> Aulin => Gain 4,392cr (122cr/ton) => 9,528cr

Again what we can buy has improved, but it's going to send us to Aulin this time because we get much better bang for the buck.

Code:
  +  At AULIN/Aulin Enterprise, Buy:
  |     12 x Agri-Medicines                 @        783cr each,      9,396cr total,
  |      7 x Biowaste                       @         18cr each,        126cr total,
  |   9,528cr => Aulin -> BD+47 2112 -> Wyrd => Gain 3,950cr (207cr/ton) => 13,478cr

We've broken 10k credits already! But this time it's telling us to only take a partial load and a mixed load at that.

What happened here is actually an example of the more complex case I described earlier on.

Code:
  +  At WYRD/Vonarburg Co-operative, Buy:
  |     36 x Fish                           @        358cr each,     12,888cr total,
  |   13,478cr => Wyrd -> BD+47 2112 -> Aulin => Gain 10,260cr (285cr/ton) => 23,738cr
  +  At AULIN/Aulin Enterprise, Buy:
  |     30 x Agri-Medicines                 @        783cr each,     23,490cr total,
  |      2 x Pesticides                     @         97cr each,        194cr total,
  |      3 x Biowaste                       @         18cr each,         54cr total,
  |   23,738cr => Aulin -> BD+47 2112 -> Wyrd => Gain 9,352cr (267cr/ton) => 33,090cr

This round-trip was the most profitable connection we could find for a route this long. But it was incorporated.

Code:
  +  At WYRD/Vonarburg Co-operative, Buy:
  |     36 x Fish                           @        358cr each,     12,888cr total,
  |   33,090cr => Wyrd -> BD+47 2112 => Gain 10,404cr (289cr/ton) => 43,494cr
 <-< Olivas Settlement gaining 43,394cr => 43,494cr total

It finishes off with a strange foray to Olivas. What's that about? Well, we'd told it we wanted to make 8 hops, and from Vonarburg, this was the best deal outbound it could find.

If we do the same run with 9 hops, it replaces the trip with Olivas to a return to Aulin, and then it goes to Romanenko for the final drop.

How much more profitable was this journey than a corresponding round-trip run between chango and rakapila?

Code:
$ ./trade.py run --ship cobra --from chango --cr 100 --hops 8 --avoid aulinenter  --avoid morgor --avoid dahan --avoid asellus --avoid ross1015 --avoid lhs2887 --avoid bolg --margin 0
I BOOTIS/Chango Dock -> I BOOTIS/Chango Dock:
 >-> At I BOOTIS/Chango Dock, Buy: 6 x Algae,
  +  At RAKAPILA/Stone Enterprise, Buy: 32 x Biowaste,
  +  At I BOOTIS/Chango Dock, Buy: 36 x Food Cartridges,
  +  At RAKAPILA/Stone Enterprise, Buy: 13 x Dom. Appliances, 10 x Biowaste,
  +  At I BOOTIS/Chango Dock, Buy: 36 x Food Cartridges,
  +  At RAKAPILA/Stone Enterprise, Buy: 28 x Dom. Appliances, 8 x Biowaste,
  +  At I BOOTIS/Chango Dock, Buy: 36 x Food Cartridges,
  +  At RAKAPILA/Stone Enterprise, Buy: 36 x Dom. Appliances,
 <-< Chango Dock gaining 24,830cr => 24,930cr total

Sticking to our round trip would have cost us 20k in the last 4 hops.


About speed: Its amazing, and you stated with some tweaking it could be even be much better/faster. Should TD ever becoming not fast enough, you could always go the MT route - if you deem that needed.

Multi-threading isn't a magic wand that makes things faster. But given that I'm considered to be something of an expert in multi-threading, I'm sure I'll consider the option if TD reaches a point where making it multi-threaded would have any kind of benefit.

As I stated before: I can see this become the engine of choice for GUI builders - if optional JSON/XML output is implemented. Is that something you would like to pursue/see happen?

It shouldn't be terribly difficult for someone to make TD output routes in JSON or XML, or simply use TD as a module from their code if they write in Python. At least one GUI developer has actually ported the TD code to another language to use in their tool.
 
Last edited:
Excellent..
So, basically I can open up my cmd prompt..
run emdn-tap
Open another cmd prompt for my trade.py calculations

Yep, that's what I do (although I use 'git bash' from msysgit because I'm more comfortable with a linux-like command prompt, hehe)

Run cleanup once in awhile.

Yep - I'll make emdn-tap.py do that periodically on its own, eventually.

And be all good.. correct??

Correct.

Also..am I correct in saying that I do Not need to run Andreas EMDN and firehose for this to work??

Correct; the advantage of running it is that when you dock at a station, you'll generate price updates to the firehose (try running ED in a window so you can see marketdump and emdn-tap at the same time, and go to the commodities market).

So - marketdump is actually written in Python, Andreas is just using "py2exe" to ship it as an installable.

Maybe we can persuade him to make it support 3rd party modules so that you can do something like emdn-tap from the same process.

OTOH if someone wants to tie the two together in a single python process, I'd be happy to include that with TD.
 
Think this depends on whether you allowed Python to add itself to the system PATH during installation and/or whether you made it available for all users.

If you chose not to do those things, then you won't have access to "pip" from the command line without doing what Rikkles describes.

Yes you are right. I'm using Windows' PowerShell which doesn't seem to take the system environment variables properly. If I use cmd then all is correct.

I'm such a disaster with Windows... Only use it for games, for everything else there's unix variants.
 
Yes you are right. I'm using Windows' PowerShell which doesn't seem to take the system environment variables properly. If I use cmd then all is correct.

I'm such a disaster with Windows... Only use it for games, for everything else there's unix variants.

You can get a full bash clone (Start >> git bash) with the windows git binaries: http://msysgit.github.io/

-Oliver
 
It just expects the file to exist, hence the "echo >data\tradedangerous.prices". Try it.

Windows is so weird... if I run that command under cmd, then it saves "ECHO is on" in the file itself, hence failing the program with a proper
Code:
Expecting: '@ SYSTEM / Station'.
Got: 'ECHO is on'

If I run the command under PowerShell, then it saves a CR+LF in the file, and crashes the program hard with an encode error.

Moral of the story: don't assume that touching a cat equals to an echo :)

Moral #2: going to download git for windows. I'm done with dealing with these ridiculous pseudo CLIs.
 
Last edited:
After two hours of testing the first stuff seems to work. I'm not sure about your 26 Draconis system in your script. Example: trade.py run --sh "Viper" --ho 2 --from "26 Draconis" --cr 999999 --ins 1000

The error message is pretty long.

Traceback (most recent call last):
File "trade.py", line 745, in <module>
main()
File "trade.py", line 737, in main
return args.proc(args)
File "trade.py", line 407, in runCommand
processRunArguments(args)
File "trade.py", line 340, in processRunArguments
originStation = tdb.lookupStation(originName)
File "c:\Users\xxx\Desktop\kfsone-tradedangerous-3eddcf579641\tradedb.py", line 530, in lookupStation
raise ValueError("System '%s' has %d stations, please specify a station instead." % (name, len(system.stations)))
ValueError: System '26 Draconis' has 0 stations, please specify a station instead.

The rest seems to be quite ok.
rTDVL.jpg


Edit 1:Maybe we should think about a "more parseable" output for a better output display. :)
Edit 2: Is there a full reference of your work? I am not a coder at all, I only attended 2 lectures of object-oriented coding. So bear with me if something goes wrong.
Download: http://sorgenkind.info/ed/TradeDangerousGUI.exe
Put the file into your folder where the trade.py file is located. Microsoft's .Net 4.0 Framework is required.
Edit 3: Found the command line options. WHAT ZEE FUUUK?????? You have way too much time LOL. This is a holycrapload of work to implement. But since I'm on vacation right now, I'll see what I can do. I need some testers for this. :)

Source code (C#):
Code:
<Window x:Class="TradeDangerousGUI.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
        Title="TradeDangerousGUI" Height="319" Width="357" MinWidth="357" MinHeight="319">
    <Grid Margin="0,0,2,5">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="90"/>
            <ColumnDefinition Width="136"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="146"/>
            <RowDefinition Height="Auto" MinHeight="29"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <StackPanel HorizontalAlignment="Left" Height="132" VerticalAlignment="Top" Width="78" Margin="10,10,0,0">
            <Label x:Name="lbShip" Content="Ship:" HorizontalAlignment="Left" VerticalAlignment="Top" Width="52" Height="26"/>
            <Label Content="Hops:" HorizontalAlignment="Left" VerticalAlignment="Top" Width="68" Height="26"/>
            <Label x:Name="lbFrom" Content="From:" HorizontalAlignment="Left" VerticalAlignment="Top" Width="52" Height="26"/>
            <Label x:Name="lbCredits" Content="Credits:" HorizontalAlignment="Left" VerticalAlignment="Top" Width="52" Height="26"/>
            <Label x:Name="lbCredits_Copy" Content="Insurance:" HorizontalAlignment="Left" VerticalAlignment="Top" Width="68" Height="26"/>
        </StackPanel>
        <StackPanel Height="132" Margin="10,10,0,0" VerticalAlignment="Top" Grid.Column="1" HorizontalAlignment="Left" Width="126">
            <ComboBox x:Name="cbShips" VerticalAlignment="Top" SelectionChanged="ComboBox_SelectionChanged" SelectedIndex="0" Height="26" Margin="0,0,10,0">
                <ComboBoxItem Content="Viper"/>
                <ComboBoxItem Content="Eagle"/>
                <ComboBoxItem Content="Sidewinder"/>
                <ComboBoxItem Content="Hauler"/>
                <ComboBoxItem Content="Cobra"/>
                <ComboBoxItem Content="Lakon Type 6"/>
                <ComboBoxItem Content="Lakon Type 9"/>
                <ComboBoxItem Content="Anaconda"/>
            </ComboBox>
            <xctk:IntegerUpDown x:Name="intHops" FormatString="N0" Value="2" Increment="1" Minimum="1" Height="26" VerticalAlignment="Top" Margin="0,0,10,0"/>
            <ComboBox x:Name="cbFrom" VerticalAlignment="Top" SelectedIndex="3" Height="26" Margin="0,0,10,0">
                <ComboBoxItem Content="26 Draconis"/>
                <ComboBoxItem Content="Acihaut"/>
                <ComboBoxItem Content="Aganippe"/>
                <ComboBoxItem Content="Asellus Primus"/>
                <ComboBoxItem Content="Aulin"/>
                <ComboBoxItem Content="Aulis"/>
                <ComboBoxItem Content="BD+47 2112"/>
                <ComboBoxItem Content="BD+55 1519"/>
                <ComboBoxItem Content="Bolg"/>
                <ComboBoxItem Content="Chi Herculis"/>
                <ComboBoxItem Content="CM Draco"/>
                <ComboBoxItem Content="Dahan"/>
                <ComboBoxItem Content="DN Draconis"/>
                <ComboBoxItem Content="DP Draconis"/>
                <ComboBoxItem Content="Eranin"/>
                <ComboBoxItem Content="G 239-25"/>
                <ComboBoxItem Content="GD 319"/>
                <ComboBoxItem Content="h Draconis"/>
                <ComboBoxItem Content="Hermitage"/>
                <ComboBoxItem Content="i Bootis"/>
                <ComboBoxItem Content="Ithaca"/>
                <ComboBoxItem Content="Keries"/>
                <ComboBoxItem Content="Lalande 29917"/>
                <ComboBoxItem Content="LFT 1361"/>
                <ComboBoxItem Content="LFT 880"/>
                <ComboBoxItem Content="LFT 992"/>
                <ComboBoxItem Content="LHS 2819"/>
                <ComboBoxItem Content="LHS 2884"/>
                <ComboBoxItem Content="LHS 2887"/>
                <ComboBoxItem Content="LHS 3006"/>
                <ComboBoxItem Content="LHS 3262"/>
                <ComboBoxItem Content="LHS 417"/>
                <ComboBoxItem Content="LHS 5287"/>
                <ComboBoxItem Content="LHS 6309"/>
                <ComboBoxItem Content="LP 271-25"/>
                <ComboBoxItem Content="LP 275-68"/>
                <ComboBoxItem Content="LP 64-194"/>
                <ComboBoxItem Content="LP 98-132"/>
                <ComboBoxItem Content="Magec"/>
                <ComboBoxItem Content="Meliae"/>
                <ComboBoxItem Content="Morgor"/>
                <ComboBoxItem Content="Nang Ta-khian"/>
                <ComboBoxItem Content="Naraka"/>
                <ComboBoxItem Content="Opala"/>
                <ComboBoxItem Content="Ovid"/>
                <ComboBoxItem Content="Pi-fang"/>
                <ComboBoxItem Content="Rakapila"/>
                <ComboBoxItem Content="Ross 1015"/>
                <ComboBoxItem Content="Ross 1051"/>
                <ComboBoxItem Content="Ross 1057"/>
                <ComboBoxItem Content="Styx"/>
                <ComboBoxItem Content="Surya"/>
                <ComboBoxItem Content="Tilian"/>
                <ComboBoxItem Content="WISE 1647+5632"/>
                <ComboBoxItem Content="Wyrd"/>

            </ComboBox>
            <xctk:IntegerUpDown x:Name="intCredits" FormatString="N0" Value="1000" Increment="1000" Margin="0,0,10,0" Minimum="0" Height="26" VerticalAlignment="Top"/>
            <xctk:IntegerUpDown x:Name="intInsurance" FormatString="N0" Value="1000" Increment="1000" Margin="0,0,10,0" Minimum="0" Height="26" VerticalAlignment="Top"/>
        </StackPanel>
        <Button x:Name="btCalculate" Content="Calculate" HorizontalAlignment="Left" VerticalAlignment="Top" Width="76" Height="22" Margin="10,5,0,0" Grid.Row="1" Click="btCalculate_Click"/>
        <StackPanel Grid.Column="2" Height="100" Margin="2,10,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="111">
            <RadioButton x:Name="rbStandardDetails" Content="Default details" GroupName="rbgrpDetails"/>
            <RadioButton x:Name="rbMoreDetails" Content="More details" GroupName="rbgrpDetails"/>
            <RadioButton x:Name="rbEvenMoreDetails" Content="Even more details" GroupName="rbgrpDetails"/>
        </StackPanel>
        <TextBox x:Name="tbResult" Grid.ColumnSpan="3" Margin="10" Grid.Row="2" TextWrapping="Wrap" Text="Hit calculate, Commander!" IsReadOnly="True"/>
    </Grid>
</Window>

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.IO;

namespace TradeDangerousGUI
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

        }

         private void btCalculate_Click(object sender, RoutedEventArgs e)
        {


            string strDetails = "";

            if (rbStandardDetails.IsChecked == true)
                strDetails = "";
            else if (rbMoreDetails.IsChecked == true)
                strDetails = " -v";
            else if (rbEvenMoreDetails.IsChecked == true)
                strDetails = " -vv";
            string strShellCommand = "";



            strShellCommand = "trade.py run" + strDetails + " " + "--sh \"" + cbShips.Text + "\" --ho " + intHops.Value.ToString() + " --from \"" + cbFrom.Text + "\" --cr " + intCredits.Value.ToString() + " --ins " + intInsurance.Value.ToString();

            var process = new Process();
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.StartInfo.WorkingDirectory = Directory.GetCurrentDirectory();
            process.StartInfo.FileName = "python.exe";
            process.StartInfo.Arguments = strShellCommand;

            process.Start();
            tbResult.Text = "";
            tbResult.Text = strShellCommand + Environment.NewLine + Environment.NewLine;
            while (process.StandardOutput.Peek() > -1)
            {
                tbResult.AppendText(process.StandardOutput.ReadLine() + Environment.NewLine );
            }

            while (process.StandardError.Peek() > -1)
            {
                tbResult.AppendText(process.StandardError.ReadLine() + Environment.NewLine);
            }
            process.WaitForExit();


        }
    }
}
 
Last edited:
Speaking of lots of time, today I'm rather short on it, wife has demanded I set up my desk so the house isn't so cluttered
Desk-of-Warcraft.jpg
so I haven't given what you've done the proper look it deserves, but it looks good. It's probably possible to make it use the .db file (there are probably .net drivers) to seed things like the drop down.

After two hours of testing the first stuff seems to work. I'm not sure about your 26 Draconis system in your script. Example: trade.py run --sh "Viper" --ho 2 --from "26 Draconis" --cr 999999 --ins 1000

The error message is pretty long.

Traceback (most recent call last):
File "trade.py", line 745, in <module>
main()
File "trade.py", line 737, in main
return args.proc(args)
File "trade.py", line 407, in runCommand
processRunArguments(args)
File "trade.py", line 340, in processRunArguments
originStation = tdb.lookupStation(originName)
File "c:\Users\xxx\Desktop\kfsone-tradedangerous-3eddcf579641\tradedb.py", line 530, in lookupStation
raise ValueError("System '%s' has %d stations, please specify a station instead." % (name, len(system.stations)))
ValueError: System '26 Draconis' has 0 stations, please specify a station instead.

Python errors tend to be in reverse callstack order, that is the most significant message is at the bottom - it takes some getting used to :) Ultimately, what all of that error says is:

Code:
ValueError: System '26 Draconis' has 0 stations, please specify a station instead.

Probably a bug in processAvoids.

Lastly: If you want to make a project of your GUI and/or want to experiment with GIT, I strongly encourage you to make a bitbucket or github account and either check out Atlassian's SourceTree (http://sourcetreeapp.com/) or the Git SCM support in MS Visual Studio 2013. If Git is a pain in the ass, SourceTree is hemmaroid cream .. with pheremones and stuff :)
 

wolverine2710

Tutorial & Guide Writer
Found Access again. Thanks for the very detailed answers. Gonna reread them. again next week. Arm TD has 2 resources, manual file and Emdn-Tap. Someone created Elite-metrics a Webapi Fed by Emden. The API gives back stuff like latest Prices. So no Need to have Emdn-tap Running. Perhaps usefull for TD?
 
Found Access again. Thanks for the very detailed answers. Gonna reread them. again next week. Arm TD has 2 resources, manual file and Emdn-Tap. Someone created Elite-metrics a Webapi Fed by Emden. The API gives back stuff like latest Prices. So no Need to have Emdn-tap Running. Perhaps usefull for TD?

You don't have to have EMDN-Tap running to use TD. EMDN-Tap is just a way to update the prices in the local database.

Technically, TD gets all of it's data from "data/TradeDangerous.prices" which is a human-readable file (also human editable).

The "local database" is a machine-readable form of the data. If you change the .prices file and then run trade.py, it rebuilds the db file - this is an efficiency optimization, a "cache". Open "TradeDangerous.prices" in an editor, fly the game, dock at a station, compare the entry for the station in .prices against the game, make your changes, save, and trade.py will pick up the changes next time you run it.

If you instead go to a web-based API, you're going to experience a lot of hurt unless that API essentially does all the work for you.

The problem that TD is trying to solve is officially described as an "NP Problem" [http://en.wikipedia.org/wiki/NP_(complexity)]. Most of the other profit calculators are approximating a result set by using a tweak of the rules.

For example: You have a Lakon Type 9, 228 capacity, 20,000 credits at StationA. The most profitable possible trade is ItemA StationA->StationB for 8000cr each profiting 1100cr/ton. The least profitable trade is ItemZ StationA->StationC for 85cr each profiting 55cr/ton.

Some calculators only bother to check highest profitability. ItemA wins, meaning you can make a maximum of 2200cr.

Others will try and fill up your hold with other trades you can make StationA->StationB, but after buying the gold you only have 4000cr left. The problem with this approach is that the individually most profitable items are usually the most expensive. So they perhaps boost you to 2800cr for a run.

You can comfortably afford a full load of ItemZ. 228 x 55cr profit = 12540kcr profit; that's 10k more than the obvious choices.

I also documented here another more complex example of how TD works harder for your earnings ;)

In order to do this efficiently, you need to have a lot of data to form constraints with early on. Fundamentally, one of the things that makes a problem NP is that for some portion of the problem where you can't know what data can be discarded in advance - you *have* to do a computation with it to *prove* that it's not required: If I ask you to give me the largest number in this list (1,2,3,4,5) that's easy, but if I ask you which number in this list uses the most pixels (1,2,3,4,5) in helvetica you can't answer that without doing some work.

If you try and use TD from a web-based API you're going to have to pull all of the data from the API in order to start forming constraints; you can't specify which stations you want data for in advance.

You could probably cache the data locally and only refresh it periodically, but you're still going to be hammering the API.

If you're ok with that, you can probably work that way, although I think the guy providing the API might feel different about that fairly quickly :)
 
Last edited:
ValueError: System '26 Draconis' has 0 stations, please specify a station instead.

Hi, TBF,

Fix checked in an pushed: using TradeDB.lookupStationExplicitly to match station names when parsing --avoids.

I've also updated the OP and the readme to hopefully help people some more.
 
Back
Top Bottom