Skip to content

User Guide

Stefan Morrell edited this page Jul 14, 2018 · 5 revisions

Contents


Getting Started!

The Basics

The core of the TD system is "trade.py", which you invoke from the command line:

Windows:

C:\Trade\> trade.py

Mac/Linux/Bash:

$ python3.6 trade.py

(or similar, dependant upon your python version)

TradeDangerous is command-line based which means that after the "trade.py" you are going to supply the parameters of the question you have, such as which tool to use, what systems to look at, etc.

The first thing you'll type after 'trade.py' is the name of the sub-command you want to invoke, such as local to find nearby stars or run to plan a trade run.

After the sub-command you'll provide parameters for the request you're making.

Command Line Parameters 101

There are some parameters that are required for a command to work, for instance the "local" command needs a System name to base its query on:

$ trade.py local Mokosh/BetheStation

There are also "modifiers". These are either a dash followed by a single letter or two dashes followed by a descriptive name.

$ trade.py local --detail Mokosh/BetheStation
$ trade.py local -v Mokosh/BetheStation

"-v" is an alias for "--detail" (think 'verbose'), so the above two commands actually do the same thing.

Note: Long-form modifiers can be shortened down to the least number of letters that makes them distinct from other modifiers used by the command. So --detail could be --de or --det, --ly-per-jump could be --ly

Some modifiers require a value; you can either type "--name value" or "--name=value", the "=" can make it easier to tell what you intended:

$ trade.py local -v --ly=12 Mokosh/BetheStation
$ trade.py local -v --ly 12 Mokosh/BetheStation

Expert note: you can stack short-form arguments, "-A -B -C -C -D" can be written as "-ABCCD".

Nobody can hear your spaces...

If you run into problems with names/words with spaces in them, you can either leave the space out (BetheStation) or use quotes:

$ trade.py local -v --ly=12 mokosh/bethestation
$ trade.py local -v --ly=12 "mokosh/bethe station"
$ trade.py local -v --ly=12 'mokosh/bethe station'

There is help...

trade.py has a lot of help, if you have a problem with a command, try

$ trade.py cmdyourstuckwith --help
e.g.
$ trade.py local --help

Conventions used in TradeDangerous

Terms

We use the term "hop" to mean picking up cargo from station A, travelling to station B and selling your cargo there.

A "jump" is entering hyperspace to travel between two different systems.

Conventions

TD generally indicates a SYSTEM NAME by displaying it in upper case while station names are displayed as a proper noun ("McDivitt Station").

The convention of SYSTEM/Station is used to qualify a station in a specific system.

You don't have to type all of it ...

TD tries to save you typing by looking things up for you, the only limit is how uniquely the thing you type identifies what you're trying to reference.

$ trade.py local "The Ascending Phoenix"
$ trade.py local TheAscendingPhoenix
$ trade.py local TheAcendingP
$ trade.py local ascendingp

But it breaks down at "phoenix":

$ trade.py local phoenix
./trade.py: System/Station lookup: "phoenix" could match BW PHOENIX or CHI ERIDANI/The Ascending Phoenix

Disambiguation

If a system name is conflicting with a station name, you can prefix it with an '@' sign

$ trade.py local @phoenix

will lookup a system maching "phoenix" (at time of writing, that's BW PHOENIX)

You can indicate a station by prefixing it with a "/"

$ trade.py local /phoenix

will only match against station names.

If you want to specify both a system name and a station name you can write this as either:

$ trade.py local chi/phoen
or
$ trade.py local @chi/phoen

This looks up all the systems that match "chi" and then searches their stations for matches with "phoen".

Let there be data

In order to do anything with TradeDangerous, you're going to need some price data.

Enter it yourself

You can manually enter or refresh data for stations as you visit them by using the "update" sub-command.

$ trade.py update BetheStation

This window is designed to closely resemble the Market Data UI in the game.

You can also use a text-editor to edit the data, see

$ trade.py update --help

When you are done editing, a copy of your changes is written to a file called "updated.prices" and then the data is loaded into the main TradeDangerous database (or "cache").

If you plan to maintain your own personal set of data, you might want to read the section entitled Local Price Data below.

Download someone else's

The other way to get data is to import it from someone else. TD has an "import" command for this purpose. You can specify a local ".prices" file (you can read about prices file in the Price Data wiki page), or you can specify a web url to download.

Another option is to use a plugin. We include a number of plugins which have variously been written for TD over the years, but the only one we currently support is EDDBlink.

EDDBlink updates market data using mirrored copies of EDDB's api files & collected data from an EDDN listener, currently running on Tromador's server.

$ trade.py import --plug=eddblink --opt=clean

See Plugin Options for options supported by this and other plugins.

If you want to use a different 3rd party .prices source, you may be able to obtain a plugin module from them.

Once you have some data, you're about ready to start using TD.

Using TradeDangerous

"run" sub-command: planning a trade run

Let's assume you're at Bethe Station in Mokosh System and your hold will carry 16 units of cargo, your ship can jump 8.56ly at a time laden and you have 20,000 credits:

$ trade.py run --from "Mokosh/Bethe Station" --credits 20000 --capacity 16 --ly-per 8.56
or just
$ trade.py run --fr=mok/beth --cr=20000 --cap=16 --ly=8.56

produces an output something like this:

MOKOSH/Bethe Station -> BD+23 3151/Houssay Port:
  MOKOSH/Bethe Station: 10 x Crop Harvesters, 3 x Basic Medicines, 3 x Biowaste,
  BD+23 3151/Bamford Ring: 16 x Tea,
  BD+23 3151/Houssay Port +16,755cr

The first line is telling us which system/station pairs this run starts and ends with; it does this because TD lets you cast your net wide. Try the same command with just the system name.

The second line suggests we start by picking up 10 crop harvesters, 3 units of basic medicines and 3 units of biowaste. Biowaste probably won't be very profitable but TD will try and get you every last red credit out of your trade runs.

The third line is our first stop, Bamford Ring in the BD+23 3151 System. Sell everything we brought with us and load up with 16 units of tea.

Then, we make a quick in-system trip to a neighboring station where we sell everything and we should have somewhere in the ballpark of 16,000cr profit.

You can add the "--detail" (alias "-v") option if you want to get more insight into the run:

$ trade.py run --fr mok/beth --cr 20000 --cap 16 --ly 8.56 -v
MOKOSH/Bethe Station -> BD+23 3151/Houssay Port:
  Load from MOKOSH/Bethe Station: 10 x Crop Harvesters (@1906cr), 3 x Basic Medicines (@281cr), 3 x Biow
aste (@30cr),
  Jump MOKOSH -> BD+23 3151
  Load from BD+23 3151/Bamford Ring: 16 x Tea (@1239cr),
  Finish BD+23 3151/Houssay Port + 16,755cr => 36,755cr

the more times you specify "--detail" (or -v, or stack like -vvv), the more detail you get:

$ trade.py run --fr mok/beth --cr 20000 --cap 16 --ly 8.56 -vvv
MOKOSH/Bethe Station -> BD+23 3151/Houssay Port:
Start CR:     20,000
Hops    :          2
Jumps   :          1
Gain CR :     16,755
Gain/Hop:    8,377.5
Final CR:     36,755

  Load from MOKOSH/Bethe Station:
       10 x Crop Harvesters      1,906cr each,     19,060cr total
        3 x Basic Medicines        281cr each,        843cr total
        3 x Biowaste                30cr each,         90cr total
  Jump MOKOSH -> BD+23 3151 => Gain 7,251cr (453.188cr/ton) => 27,251cr
  Load from BD+23 3151/Bamford Ring:
       16 x Tea                  1,239cr each,     19,824cr total
  ----------------------------------------------------------------------------
  Finish at BD+23 3151/Houssay Port gaining 16,755cr => est 36,755cr total

How did TD decide on this route?

An important note Everything TradeDangerous does is data driven. It's showing us an in-station trade here because when TD crunched all the numbers, this was the best trading opportunity it found given the constraints it had.

TradeDangerous started by making a list of stations we could start from. Because we specified a station with "--from", that's a short list. We could also have specified "--from Mokosh" and then the list would have been all the stations in Mokosh system.

Next, it looked for stations that you could reach from the starting point that were buying what Bethe is selling.

Then it applied something called "Knapsack" to find out what the most profitable combination of things Bethe has to offer is for each of those stations.

It tried buying as many crop harvesters as it could afford/fit, and it tried buying as much biowaste as it could afford/fit.

When it had found the best bets, it made a note of how much money that was going to make.

Then it took each of those "hops" with the profits made and it did the same thing; "where to next?".

How many times it does this is controlled by the "--hops" option, which defaults to 2.

If we specify just one hop:

$ trade.py run --fr mok/beth --cr 20000 --cap 16 --ly 10 -vv --hops 1
MOKOSH/Bethe Station -> LTT 15449/Roentgen Port:
  Load from MOKOSH/Bethe Station:
       10 x Crop Harvesters      1,906cr each,     19,060cr total
        3 x Basic Medicines        281cr each,        843cr total
        3 x Biowaste                30cr each,         90cr total
  Jump MOKOSH -> LTT 15449 => Gain 7,387cr (461.69cr/ton) => 27,387cr
  ----------------------------------------------------------------------------
  Finish at LTT 15449/Roentgen Port gaining 7,387cr => est 27,387cr total

We made more money selling our crop harvesters et al, so why did TD send us to a different station the first time?

The answer lies in how much money we could make on the next hop:

$ trade.py run --fr 15449/roen --cr 20000 --cap 16 --ly 10 -vv --hops 1
  Load from LTT 15449/Roentgen Port:
        3 x Natural Fabrics        392cr each,      1,176cr total
  Jump LTT 15449 -> V775 HERCULI => Gain 294cr (98cr/ton) => 20,294cr
  ----------------------------------------------------------------------------
  Finish at V775 HERCULI/Beatty Port gaining 294cr => est 20,294cr total

We can actually persuade TradeDangerous to calculate this as a single route for us using the "--via" option or "--avoid" options:

$ trade.py run --fr mok/beth --cr 20000 --cap 16 --ly 10 -vv --via roentgen
$ trade.py run --fr mok/beth --cr 20000 --cap 16 --ly 10 -vv --avoid bamfordring
MOKOSH/Bethe Station -> LTT 15449/Roentgen Port:
  Load from MOKOSH/Bethe Station:
       10 x Crop Harvesters      1,906cr each,     19,060cr total
        3 x Basic Medicines        281cr each,        843cr total
        3 x Biowaste                30cr each,         90cr total
  Jump MOKOSH -> LTT 15449 => Gain 7,387cr (461.69cr/ton) => 27,387cr
  Load from LTT 15449/Roentgen Port:
        3 x Natural Fabrics        392cr each,      1,176cr total
  Jump LTT 15449 -> V775 HERCULI => Gain 294cr (98cr/ton) => 27,681cr
  ----------------------------------------------------------------------------
  Finish at LTT 15449/Roentgen Port gaining 7,681cr => est 27,681cr total

Taking this route reduced our profit from 16,755cr to 7,681cr.

For a final contrast, lets see what happens if we let TD play out a total of 5 hops:

$ trade.py run --fr mok/beth --cr 20000 --cap 16 --ly 10 --hops 5
MOKOSH/Bethe Station -> GD 219/Mckee Ring:
  MOKOSH/Bethe Station: 10 x Crop Harvesters, 3 x Basic Medicines, 3 x Biowaste,
  BD+23 3151/Bamford Ring: 16 x Tea,
  V774 HERCULIS/Mendel Mines: 16 x Gallite,
  MOKOSH/Lubin Orbital: 7 x Superconductors, 9 x Water Purifiers,
  V775 HERCULI/Beatty Port: 12 x Silver, 3 x Power Generators, 1 x Bertrandite,
  GD 219/Mckee Ring +51,347cr

In just 5 hops, we've more than doubled our money.

Some key options of "run"

--from and --to

These let you specify the start and end station or system.

Both are optional, so you can if you want type:

$ trade.py run --cap 4 --cr 1000 --ly 7.56

and find out the most profitable newbie route in the game. It may take a really long time, though.

--hops and --jumps

"--hops" controls how many legs there are, where you stop at a station and sell your current cargo and pick up a new one.

Remember: TD tries to produce the best proffit for the total number of hops you make, and changing --hops can produce very different cargo and route recommendations.

"--jumps" controls the maximum number of systems TD will allow between station stops. So if you say "--hops 2 --jumps 3" you may have to jump 6 times in total to complete a route.

--avoid and --via

These both accept stations or systems, individually or comma separated. In addition, "--avoid" also accepts the names of items.

$ trade.py run --avoid gold   # don't trade in gold
$ trade.py run --avoid gold,sol # don't trade in gold and don't go to sol

When a station is specified: "--avoid" won't use that station as a trading point, although it may pass through the system. "--via" will require that one of the stops is at the specified station.

When a system is specified: "--avoid" will guarantee you do not pass through or stop at a station in that system; "--via" will do the opposite.

--start-jumps (aka -s)

Sometimes you wind up at a station that has crap to sell and the only places that buy it sell more crap that you can only sell back at square one -- honestly, this is a testament to the work done by Frontier in setting up the economy.

The "--start-jumps" (-s) option lets TD take stations from nearby systems into account.

Again, TD makes its decisions in a data-driven way, so if you are at a station with kick-ass profits, it will start from that.

Some times it will break you out of a potentially profitless grind.

But a lot of the time it will simply move you one hop down the sequence. In practice, I always get the route with and without "-s".

"--start-jumps" is fairly new and the jury is still out as to whether it should tell you what to take with you to the first station, because that's basically like adding another --hop.

"--max-days" (aka --max)

You can restrict TD to using recent data by setting an upper age limit (in days), e.g.

$ trade.py run --max-days=7  # data must be <= 7 days old
$ trade.py run --max 0.5 # data must be <= 1/2 day (12 hours) old

Do I really have to type all this crap?

TradeDangerous is written in Python and made Open Source and modular to enable other people to incorporate into their own systems.

If you are a windows user, you might like to try the TDHelper
This is a gui frontend to Trade Dangerous which simplifies remembering the numerous options by providing a convenient form, with load/save options and other useful functionality.

Other useful methods for saving on the typing include "Fromfiles" and ".tdrc" files.

Fromfiles: Options in a can

A "fromfile" is a plain text file with TD command line options. For instance, you could create a file for each ship specifying the --ly, --cap, --empty, etc.

You specify a fromfile on the command line by prefixing the filename with a '+'

So if you want to read "sidewinder.tdf" you would type

trade.py nav +sidewinder.tdf

Of course, that's a lot to type, and we're trying to be lazy, so just go ahead and call the file "sw" :)

trade.py nav +sw

Contents of a fromfile

A fromfile is simple: each line must correspond to one position on the command line. So, "--empty-ly 30" becomes two lines while "--ly=20" is one.

--empty-ly
30
--ly=20

Default defaults: .tdrc files

Each TD command automatically looks for a file called ".tdrc_", e.g. ".tdrc_shipvendor". Note the leading dot. If this file exists, the options are read at the start of the command line.

So if you have the following .tdrc_nav

--empty-ly
30
--ly=20
-v

and you type:

trade.py nav sol waruts -vv -ly=21

TD will behave as though you gave the command line:

trade.py nav --empty-ly 30 --ly=20 -v sol waruts -vv --ly=21

Which is equivalent to:

trade.py nav --empty-ly 30 sol waruts -vvv --ly=21

Scripts

There is a "scripts" folder, which provides a set of short-cuts for a lot of the really common stuff and a way to avoid having to keep repeating things like your ship's carrying capacity, max light years, etc. See the README.txt in that folder for more information.

I would recommend getting used to trade.py without that first.

Adding or Changing Local Price Data

Some Commanders may well wish to use TD to keep track of their own price data, without using crowdsourced data such as is available via eddb and similar.
One way to do this is to use the Elite Dangerous Market Connector (EDMC) to automatically create .prices files for every station you visit, which you can add to the database using the import command, either for each file or using wildcards

trade.py import mystation.prices
trade.py import *.prices

Other ways of editing Price Data

TradeDangerous uses a human-readable text format for price information. This is designed to closely resemble what we see in the market screens in-game.

To edit the data for a single station, use the update sub-command, e.g.

trade.py update --notepad beagle2

This will open notepad with the data for Aulin, which will look something like:

@ I BOOTIS/Beagle 2 Landing
 + Chemicals
    Explosives                 50      0        ?      -
    Hydrogen Fuels             19      0        ?      -
    Mineral Oil               100      0        ?      -
    Pesticides                 21      0        ?      -
 + Consumer Items
    Clothing                  300      0        ?      -
    Consumer Tech            1112   1111        ?    30L

"@" lines specify a system/station.

"+" lines specify a category.

The remaining lines are items, such as

Explosives    50    0    ?    -

The fields used to populate items are:

  • <item name>
  • <sale price> (how much the station pays)
  • <buying price> (how much the station charges)
  • <demand> ('?' means "we don't care")
  • <stock> ('-' means "not available")

So you can see the only item this station is selling is Consumer Tech, which the station wants 1111 credits for. The demand wasn't recorded (we generally aren't interested in demand levels since E:D doesn't seem to use them) and the items wasn't available for purchase from the station.

TD will use the 'stock' values to limit how many units it can buy. For example, if you have money to buy 30 units from a station but the .prices data says only 10 are available, TD only tell you to buy 10 units and it will fill the rest of your hold up with other stuff.

Demand and Stock both take a "supply level" value which is either "?", "-" or the number of units followed by the level: L for Low, M for Medium, H for High or ? for "don't care".

?
-
1L
23M
3402H
444?

Best Practice:

  • Leave demand as ?, neither E:D or TD use it
  • Stock quantities over 10k are usually irrelevant; you may leave them as ?,

For more details of the .prices format, see the wiki page: https://github.com/eyeonus/Trade-Dangerous/wiki/Price-Data

NOTE: The order items are listed within their category is saved between edits, so if you switch "Explosives" and "Hydrogen Fuels" and then save it, they will show that way when you edit this station again.

See trade.py update -h for more help with the update command.

Experimental GUI

There is an experimental GUI for updating prices, however it is currently deprecated and has some issues, in particular you currently have to manually size and scroll the window.

To use it, simply type:

trade.py update Aulin

or whichever station you need to update. While it is in experimental status, you'll be asked to provide an extra switch.

To save your changes, click the window's close button, don't alt-f4 or command-q.

To remove an item, set the 'paying' and 'asking' values to 0

To navigate

  • Use tab/shift-tab to cycle through cells
  • Use up/down arrows to move between rows
  • Press ENTER to move to the first column of the next line

To add items to a station, use the "-A" switch and leave the items you don't want empty.

That's nice, but I'm a programmer and I want to …

TradeDangerous is organized into modules, the key of which are:

  • trade.tradedb.TradeDB
    • Presents the main database API; it loads stations, systems, ships, items and provides query APIs for these.
  • trade.tradeenv.TradeEnv
    • Container for a bag of "properties" used across TD, such as debug level.
  • trade.tradecalc.TradeCalc
    • The best profit calculator
  • trade.tradeexcept.TradeExcept
    • Exception definitions
  • trade.mfd & trade.mfd.saitek
    • Multi-function display wrappers
  • trade.commands.commandenv.CommandEnv
    • Arg-parsing variant of TradeEnv
  • trade.commands.parsing
    • Helpers for creating argument lists for sub-commands
  • trade.commands.exceptions
    • Exceptions for sub-commands
  • trade.formatting:
    • Helper classes for presenting result sets

Minimalist usage example:

import trade
tdb = trade.TradeDB()

This creates a TradeDB instance using all-default parameters. It will take a while to complete because it loads the /entire/ database.

You can override the environment by passing a "TradeEnv", which itself can be initialized with an argparse namespace or by passing default overrides:

import tradeenv
# Defaulted:
tdenv = TradeEnv()
# Use with argparse to use command-line switches for defaults
tdenv = TradeEnv(my_parser.parse())
# Override defaults directly
tdenv = TradeEnv(debug=1, detail=2)

import tradedb
tdb = tradedb.TradeDB(tdenv)

Construction of a wholly-default TradeDB can take a while because it loads a lot of data that you often probably won't need. You can speed it up by disabling the bulk of this with:

tdb = TradeDB(tdenv, loadTrades=False)

If you subsequently need this data, call

tdb.loadTrades()

As of TD 6.0 you should need to load this data less and less. A lot of work went into refactoring the SQLite DB and introducing more "lazy loading" by functions like TradeCalc.getBestHops().

When TradeDB and TradeCalc do not currently provide built-in queries for the information you need, you can revert to the SQL Database with the TradeDB.query() and TradeDB.fetch_all() commands.