Skip to content

Commit 1abb599

Browse files
committed
Trade jobs changed and documented properly. Start selling trade pile job added. An endpoint for feedback is added. Readme updated to show all existing features
1 parent 9d55102 commit 1abb599

File tree

16 files changed

+305
-253
lines changed

16 files changed

+305
-253
lines changed

.env.local

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ FUTBOT_FUTBIN_REQUESTS_PER_SEC=1.5
2323
FUTBOT_LOG_LEVEL=debug
2424

2525
# Favourite jobs to call bunch of jobs together. Separate by comma
26-
FUTBOT_FAVOURITE_JOBS=/trade-bot/start-selling?maxRating=83,/invest/low-players?budget=70000&min=1000&max=10000&maxTargetPool=100,/invest/good-auctions?budget=40000&min=5000&max=20000
26+
FUTBOT_FAVOURITE_JOBS=/trade-bot/start-selling-trade-pile,/invest/low-players?budget=50000&min=1000&max=10000&maxTargetPool=100
2727

2828
# Speed up factor will be used to automatically slow down/speed up api calls. Leave it as 0.2 if you don't know what you are doing
2929
FUTBOT_API_QUEUE_SPEED_UP_FACTOR=0.2

README.md

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,18 @@ It's tested with FIFA 20
88
## Table of contents
99

1010
**[Use Latest stable version](#use-latest-stable-version)**<br>
11+
12+
**[Dev Mode](#dev-mode)**<br>
1113
**[Prepare (Dev Mode)](#prepare)**<br>
1214
**[Start (Dev Mode)](#start)**<br>
15+
1316
**[Existing features](#existing-features)**<br>
1417
**[Existing UI Features](#existing-ui-features)**<br>
18+
1519
**[What to do on errors](#what-to-do-on-errors)**<br>
1620
**[Disclaimer and Notes](#disclaimer-and-notes)**<br>
1721
**[Known Bugs](#known-bugs)**<br>
22+
1823
**[Discord](#discord)**<br>
1924

2025
## Use Latest stable version
@@ -26,15 +31,20 @@ When you are done with the extension, you can start the server. Server needs .en
2631
Now you are all set to use existing features described later in this documentation.
2732
**Note for people outside of Europe**: You need to change 'FUTBOT_FUT_API_ENDPOINT_OVERWRITE' value in .env file. Once you load the extension, go to fut web app and click to Futbot extension. It should tell you the endpoint. Just use that value and restart your server.
2833

29-
## Prepare (Dev Mode)
34+
## Dev Mode
35+
36+
If you have an issue starting the server from last stable version, you can execute the app directly from source code. Or if you know what you are doing, just use dev mode :)
37+
38+
### Prepare (Dev Mode)
3039

3140
`Node and yarn`
3241
Install [node](https://nodejs.org/en/) and [yarn](https://yarnpkg.com/lang/en/docs/install/). Installing yarn via installation scripts are generally easier.
3342

3443
`Config`
35-
The project needs a configuration file (.env) in order to get some user preferences and region based api endpoint (I was lazy to figure it out automatically). You can copy .env.local file as .env file if you are in europe. If you are outside of europe, there is a really small change you need to make. In order to figure out your corresponding ea server, you should open developer tools in your browser and refresh fut web application. It'll stop you from debugging by adding infinite debuggers. Just click to deactive debug points and click play. Then go to network tab and search for a url similar to 'https://utas.external.s2.fut.ea.com/ut/game/fifa20'. Only different part should be 's2'. Once you find your url, change it in .env file and you are good to go. Note: any change in .env file requires app to restart.
44+
The project needs a configuration file (.env) in order to get some user preferences and region based api endpoint. You can copy .env.local file as .env file.
45+
**Don't forget to read what's inside .env file.** Especially if you are outside of Europe or if you have/had more than one origin account (it goes years back) or if you switched platforms before.
3646

37-
## Start (Dev Mode)
47+
### Start (Dev Mode)
3848

3949
Start the server
4050

@@ -56,45 +66,48 @@ Since this server is not intented to be deployed somewhere, there is no session
5666

5767
## Existing features:
5868

59-
http://localhost:9999/club/players
60-
This just returns your players in club, not in tradepile
69+
http://localhost:9999/club/non-squad-players
70+
This just returns your players in club which are not in your actice squad and not in trade pile.
71+
The list would be used for /trade-bot/start-selling job.
6172

62-
http://localhost:9999/trade-bot/start-selling
63-
This will start 2 jobs: Clearing transfer pile and selling players who are not in your active squad.
64-
Once in a while it gets your players from club, figures a good price according to futbin/fut market data. And sells them if prices are trustable enough.
65-
`Query Paramters:` maxRating
66-
`Mindstet:` Probably you have 100s of unwanted players with a price range of 0-5000. Quickselling them actually means loosing money. You can start this selling feature and get rid of them for lowest futbin prices/lowest market buyNow prices.
73+
http://localhost:9999/trade-bot/start-selling-unused?maxRating=83
74+
http://localhost:9999/trade-bot/stop-selling-unused
75+
These will control selling players who are not in your active squad.
76+
Once in a while it gets your players from club, figures a good price according to futbin/fut market data. And sells them if prices are trustable enough.
6777

68-
http://localhost:9999/trade-bot/relist-expired
69-
This will update the sell price for and re-list expired items
78+
http://localhost:9999/trade-bot/start-selling-trade-pile
79+
http://localhost:9999/trade-bot/stop-selling-trade-pile
80+
Relisting job is pretty similar to selling unused players. Only difference is, this job will only focus on players in your trade pile. It can relist an item or you can send players to transfer list and start this job to start selling them.
7081

7182
http://localhost:9999/trade-bot/clear-pile
72-
This will clear transfer list from sold/expired items
73-
It's best to use prior to sell
83+
This will clear transfer list from sold/expired items. It will send everything to club. If there are duplicates, it'll sell them.
7484

7585
http://localhost:9999/invest/low-players?budget=50000&min=1000&max=5000&maxTargetPool=150
76-
When you start investing with a budget, a job will start to buy cheap players for cheaper (<80%) futbin prices. Since players are already cheap, it will try to use buyNow feature all the time.
77-
The job figures investment targets from most popular futbin players in 1000 - 5000 price range (can be overwritten with min max query params).
78-
Once the job finds a player with a safe price to buy, it'll buy and resell it. Sometimes you get errors on reselling because processing player time takes more than expected (5s). If you also have trade-bot/sell job running, it'll catch these players and sell for same price.
79-
The job will continue to spend all the budget for buying players.
80-
Sell prices won't be added back to actual budget.
81-
If you start this job in the night with parameters I provided, you might have ~10-20k profit in the morning.
86+
http://localhost:9999/invest/low-players-stop
87+
This job targets most liked futbin players in your min-max range. It saves the list of players (max target pool is max limit for this), calculates their prices and searches market for auctions with lower buy now price than optimal price, e.g. buy at 59th min.
88+
You can set FUTBOT_PROFIT_MARGIN in .env file to effect this calculation.
89+
`Known bug`: Very rarely futbin has wrong prices with big difference. The bot still buys them, thinking they are cheap. This will be fixed in future releases.
8290

8391
http://localhost:9999/invest/good-auctions?budget=50000&min=5000&max=10000
84-
This is similar to low players investor job. Only difference is, this job is focused on expensive players with low current bid amounts. This job searches market for auctions, which will expire soon. In these auctions, the task will try to find players for 20% profit margin and bid accordingly.
92+
http://localhost:9999/invest/good-auctions-stop
93+
This is similar to low players investor job. Only difference is, this job is focused on expensive players with low current bid amounts, e.g. trades with 1min remaining.
94+
You can set FUTBOT_PROFIT_MARGIN in .env file to effect this calculation.
95+
`Known issue`: Currently this job takes a bit long time to put an offer and it rarely buy players. You can use low-player invest job till this is fixed in future releases.
8596

8697
http://localhost:9999/jobs/start-favourites
87-
You can start a set of jobs from one endpoint. You can configure this in .env file. There is an example in .env.local file. Look for FUTBOT_FAVOURITE_JOBS value in there and configure for your own needs.
98+
You can start a set of jobs from one endpoint. You can configure this in .env file. Look for FUTBOT_FAVOURITE_JOBS value in there and configure for your own needs.
8899

89100
http://localhost:9999/jobs/list
90101
http://localhost:9999/jobs/stop-all
91102
http://localhost:9999/jobs/resume-all
92103
These endpoints are pretty straitghforward. They show an overall look of currently running tasks/jobs. They also include their individual reports.
93104

94-
http://localhost:9999/stats
105+
http://localhost:9999/stats
95106
Shows statistics about api usage for fut & futbin.
96107

97-
There are more endpoints to use. But I don't think they are worth to mention in this point. You can read them in files named `*.*-app.ts`
108+
http://localhost:9999/feedback
109+
Feedback combines /stats, /jobs/list and .env file values to show state of your application.
110+
It's usefull when you want to ask a question, report a bug, give a feedback or just share big profits!
98111

99112
## Existing UI Features
100113

lib/api/fut-api/service.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,12 @@ export namespace fut {
2828
export type Platform = 'pc' | 'ps' | 'xbox';
2929
export type Quality = 'bronze' | 'silver' | 'gold' | 'special';
3030

31-
export async function getClubPlayers(page = 0): Promise<ItemData[]> {
31+
export async function getClubPlayers(
32+
page = 0,
33+
count = 100
34+
): Promise<ItemData[]> {
3235
const response = await futApi.get(
33-
`/club?sort=desc&type=player&start=${page * 100}&count=100`
36+
`/club?sort=desc&type=player&start=${page * count}&count=${count}`
3437
);
3538
return response.data.itemData;
3639
}

lib/app.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { authApp } from './auth';
1010
import { autoBuyerApp } from './auto-buyer/auto-buyer-app';
1111
import { clubApp } from './club/club-app';
1212
import { startCorsProxy } from './cors-proxy';
13+
import { feedbackApp } from './feedback';
1314
import { investApp } from './invest/invest-app';
1415
import { jobsApp } from './jobs';
1516
import { logger } from './logger';
@@ -35,6 +36,7 @@ app.use('/stats', statsApp);
3536
app.use('/invest', investApp);
3637
app.use('/auto-buyer', autoBuyerApp);
3738
app.use('/jobs', jobsApp);
39+
app.use('/feedback', feedbackApp);
3840

3941
app.get('/ping', (req, res) => res.send('pong'));
4042

lib/club/club-app.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
import * as express from 'express';
2-
import { fut } from '../api';
32
import { playerService } from '../player';
43
import { club } from './club-service';
54

65
export const clubApp = express();
76

8-
clubApp.get('/players', async (req, res) => {
9-
const players: fut.ItemData[] = await fut.getClubPlayers(req.query.page);
10-
res.send(players);
11-
});
12-
13-
clubApp.get('/players-to-sell', async (req, res) => {
7+
clubApp.get('/non-squad-players', async (req, res) => {
148
try {
15-
let players: any = await club.getPlayersToSell();
9+
let players: any = await club.getNonSquadTradeablePlayers();
1610
players = players.map(p => playerService.readable(p));
1711
res.send(players);
1812
} catch (e) {

lib/club/club-service.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,29 @@
11
import { fut } from '../api';
2-
import { playerService } from '../player';
32
import { filterPlayers } from '../player/player-utils';
43

54
export namespace club {
6-
export async function getPlayersToSell() {
5+
export async function getNonSquadPlayers() {
76
const batch = 100;
8-
const squadPlayers = await fut.getSquadPlayerIds();
9-
const squadPlayerIDs = squadPlayers.map(p => p.id);
7+
const squadPlayerIDs = (await fut.getSquadPlayerIds()).map(p => p.id);
108
const playerCount = (await fut.getClubItemMeta()).filter(
119
d => d.type === 'players'
1210
)[0].typeValue;
1311
let players: fut.ItemData[] = [];
1412
for (let i = 0; i < playerCount / batch; i++) {
15-
players = players.concat(await fut.getClubPlayers(i));
13+
players = players.concat(await fut.getClubPlayers(i, batch));
1614
}
1715

1816
if (!players) {
1917
return null;
2018
}
2119

22-
players = players.filter(p => squadPlayerIDs.indexOf(p.id) === -1);
23-
players = players.filter(p => p.itemState === 'free');
24-
players = filterPlayers(players, {
25-
tradeableOnly: true
26-
});
20+
return players.filter(p => squadPlayerIDs.indexOf(p.id) === -1);
21+
}
2722

28-
return players;
23+
export async function getNonSquadTradeablePlayers() {
24+
const players = await getNonSquadPlayers();
25+
return filterPlayers(players, { tradeableOnly: true }).filter(
26+
p => p.itemState === 'free'
27+
);
2928
}
3029
}

lib/feedback/index.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import Axios from 'axios';
2+
import * as express from 'express';
3+
import { envConfig } from '../config';
4+
5+
export const feedbackApp = express();
6+
7+
feedbackApp.get('', async (req, res) => {
8+
const selfAddress = `http://localhost:${process.env.PORT || 9999}`;
9+
const stats = (await Axios.get(`${selfAddress}/stats`)).data;
10+
const jobs = (await Axios.get(`${selfAddress}/jobs/list`)).data;
11+
const config = envConfig();
12+
13+
res.send(JSON.stringify({ stats, jobs, config }, null, 2));
14+
});

lib/invest/invest-app.ts

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,8 @@
11
import * as express from 'express';
2-
import { fut } from '../api';
32
import { investService } from './invest-service';
43

54
export const investApp = express();
65

7-
investApp.get('/players', async (req, res) => {
8-
const { budget, min, max } = getBudgetMinMax(req.query);
9-
const platform = await fut.getPlatform();
10-
const priceKey = `${platform.toLowerCase()}_price`;
11-
if (!budgetMinMaxQueryCheck(res, Number.MAX_VALUE, min, max)) {
12-
return;
13-
}
14-
15-
res.send(
16-
await investService.getTargets({
17-
page: 1,
18-
[priceKey]: `${min}-${max}`
19-
})
20-
);
21-
});
22-
236
investApp.get('/low-players', async (req, res) => {
247
const { maxTargetPool } = req.query;
258
const { budget, min, max } = getBudgetMinMax(req.query);
@@ -46,6 +29,11 @@ investApp.get('/good-auctions', async (req, res) => {
4629
res.send(investService.startGoodAuctionInvest({ budget, min, max }));
4730
});
4831

32+
investApp.get('/good-auctions-stop', async (req, res) => {
33+
investService.clearGoodAuctionInvest();
34+
res.send('OK');
35+
});
36+
4937
function getBudgetMinMax(query: any) {
5038
const { budget, min, max } = query;
5139
return {

lib/jobs/job.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export class Job {
4646
private id: string;
4747
private task: () => Promise<void>;
4848
private avgExecTimeS: number = 0;
49+
private executing = false;
4950

5051
constructor(protected name: string, private timesPerMin: number) {
5152
this.start = this.start.bind(this);
@@ -86,6 +87,14 @@ export class Job {
8687

8788
this.source = interval(min / this.timesPerMin).pipe(startWith(null));
8889
this.sub = this.source.subscribe(async () => {
90+
if (this.executing) {
91+
logger.warn(
92+
`${this.id} was to slow to execute on previos run. Skipping this one.`
93+
);
94+
return;
95+
}
96+
97+
this.executing = true;
8998
const start = new Date().getTime();
9099
this.execTime++;
91100
logger.debug(`Executing JOB[${this.id}]`);
@@ -98,6 +107,7 @@ export class Job {
98107
logger.debug(`JOB[${this.id}] execution finished in ${t}`);
99108
this.avgExecTimeS =
100109
((this.execTime - 1) * this.avgExecTimeS + t) / this.execTime;
110+
this.executing = false;
101111
});
102112
}
103113
}

lib/trader/jobs/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './sell-unused-players';
2+
export * from './sell-trade-pile-players';

0 commit comments

Comments
 (0)