-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
07485e5
commit 44f66a6
Showing
7 changed files
with
228 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { trading } from '../../../config.json'; | ||
import { Item, ItemPrice } from './types'; | ||
|
||
export function isTrash(item: ItemPrice): boolean { | ||
return calculatePrice(item) <= trading.trashValue; | ||
} | ||
|
||
export function containsUnmarketable(items: Item[], callback: (items: Item[]) => void): boolean { | ||
const unmarketable = items.filter((item) => !item.marketable); | ||
if (unmarketable.length > 0) { | ||
callback(unmarketable); | ||
return true; | ||
} else return false; | ||
} | ||
|
||
export function calculatePrice({ median_price, lowest_price }: ItemPrice): number { | ||
return lowest_price > median_price ? lowest_price : median_price + lowest_price / 2; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import axios from 'axios'; | ||
import { error, info } from '../logger'; | ||
import { ItemPrice, Item } from './types'; | ||
import { calculatePrice, isTrash } from './analyzer'; | ||
|
||
export async function getItemPrice({ appid, market_hash_name }: Item): Promise<ItemPrice> { | ||
return new Promise<ItemPrice>(async (resolve, reject) => { | ||
const params = { appid, currency: 1, market_hash_name }; | ||
try { | ||
const data = await axios.get('http://steamcommunity.com/market/priceoverview', { params }); | ||
info('Received a response for the request on steamcommunity'); | ||
return resolve(parseData(data)); | ||
} catch (err) { | ||
error('Received and error when getting steam price overview:'); | ||
return reject(err); | ||
} | ||
}); | ||
} | ||
|
||
export async function getAllItemsPrice(items: Item[]) { | ||
const prices: ItemPrice[] = []; | ||
for(let item of items) { | ||
prices.push(await getItemPrice(item)) | ||
} | ||
return prices; | ||
} | ||
|
||
function parseData({ success, lowest_price, volume, median_price }: any): ItemPrice { | ||
return { | ||
success, | ||
volume: Number(volume), | ||
lowest_price: cleanPrice(lowest_price), | ||
median_price: cleanPrice(median_price) | ||
}; | ||
} | ||
|
||
function cleanPrice(price: string): number { | ||
return Number(price.substring(1)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import { info, warn } from '../logger'; | ||
import config from '../../../config.json'; | ||
import { getAllItemsPrice } from './market'; | ||
import { Offer, Community } from './types'; | ||
import { containsUnmarketable, isTrash, calculatePrice } from './analyzer'; | ||
import { acceptOffer, declineOffer, Reason } from './trader'; | ||
|
||
const { ownerIds, tradeWith0Profit } = config.trading; | ||
|
||
export async function process(offer: Offer, community: Community): Promise<void> { | ||
info('Received an offer'); | ||
|
||
const { partner, message, itemsToGive, itemsToReceive } = offer; | ||
|
||
if (message && message.length > 0) { | ||
info('This offer came with a message:', message); | ||
} | ||
|
||
if (offer.isGlitched()) { | ||
warn('Received glitched offer, declining...'); | ||
return declineOffer(offer, Reason.GLITCHED); | ||
} | ||
|
||
if (ownerIds.includes(partner.getSteamID64())) { | ||
info('Trade partner is owner'); | ||
return acceptOffer(offer); | ||
} | ||
|
||
info(`All our items are: ${itemsToGive.map((item) => item.name)}`); | ||
|
||
info(`Their items are: ${itemsToReceive.map((item) => item.name)}`); | ||
|
||
if (itemsToReceive.length < 1) { | ||
info('Their item list are empty. declining...'); | ||
return declineOffer(offer, Reason.NEGATIVE_PROFIT); | ||
} else { | ||
if (containsUnmarketable(itemsToReceive, (items) => info(`There's unmarketable itens in the trade: ${items}`))) { | ||
info('Declining trade'); | ||
return declineOffer(offer, Reason.UNMARKETABLE_ITEM); | ||
} | ||
|
||
const isGift = itemsToGive.length < 1; | ||
|
||
info(isGift ? 'Our item list are empty. Accepting gift...' : 'They have items to trade. Analyzing...'); | ||
info('Getting market prices.'); | ||
|
||
const receiveItemsPrices = await getAllItemsPrice(itemsToReceive); | ||
|
||
if (receiveItemsPrices.some(isTrash)) { | ||
warn('Trade received with in the trash limit. Declining offer'); | ||
return declineOffer(offer, Reason.TRASH_LIMIT); | ||
} | ||
|
||
const receivePrice = receiveItemsPrices.map(calculatePrice).reduce((a, b) => a + b); | ||
|
||
const givePrice = (await getAllItemsPrice(itemsToGive)).map(calculatePrice).reduce((a, b) => a + b); | ||
|
||
info(`Our price are: '$${givePrice}' and their price are: '$${receivePrice}'`); | ||
|
||
if (isGift) { | ||
info('Accepting gift'); | ||
return acceptOffer(offer, receivePrice); | ||
} else { | ||
if (givePrice >= receivePrice) { | ||
info('We are overpaying. Declining offer...'); | ||
return declineOffer(offer, Reason.NEGATIVE_PROFIT); | ||
} else { | ||
if (givePrice == receivePrice) { | ||
info('This trade profit equal to 0'); | ||
if (!tradeWith0Profit) { | ||
info(`The flag 'tradeWith0Profit' is false. Declining offer...`); | ||
return declineOffer(offer, Reason.ZERO_PROFIT); | ||
} else { | ||
info(`Trading in the same way as the flag 'tradeWith0Profit' is true`); | ||
} | ||
} | ||
|
||
const profit = receivePrice - givePrice; | ||
|
||
info(`Our profit is ${profit}. Accepting offer...`); | ||
return acceptOffer(offer, profit); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { Offer } from './types'; | ||
import { info, warn, error } from '../logger'; | ||
|
||
export enum Reason { | ||
TRASH_LIMIT = 'Exists one or more itens with an value lower than the trash limit', | ||
GLITCHED = 'This trade was glitched', | ||
NEGATIVE_PROFIT = 'He proposed an offer that our profit is negative', | ||
UNMARKETABLE_ITEM = 'Exists one or more itens that are unmarketable', | ||
ZERO_PROFIT = `This trade have both sides at the same price and the flag 'tradeWith0Profit' is false` | ||
} | ||
|
||
export async function declineOffer(offer: Offer, reason: Reason) { | ||
await offer.decline((err) => { | ||
if (err) { | ||
error('Was thrown an error while declining this offer.', err); | ||
return; | ||
} | ||
warn(`Declined the offer. Reason: '${reason}'`); | ||
}); | ||
} | ||
|
||
export async function acceptOffer(offer: Offer, profit?: number) { | ||
await offer.accept((err) => { | ||
if (err) { | ||
error('Was thrown an error while accepting this offer.', err); | ||
return; | ||
} | ||
info(`Accepted the offer with the profit of ${profit}`); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
export interface Partner { | ||
getSteamID64(): number; | ||
} | ||
|
||
export interface Item { | ||
market_hash_name: string; | ||
name: string; | ||
appid: number; | ||
amount: number; | ||
marketable: boolean; | ||
tradeable: boolean; | ||
commodity: boolean; | ||
} | ||
|
||
export interface ItemPrice { | ||
success: boolean; | ||
lowest_price: number; | ||
volume: number; | ||
median_price: number; | ||
} | ||
|
||
export interface Offer { | ||
isGlitched: () => boolean; | ||
accept: (err: (err: any) => void) => void; | ||
decline: (err: (err: any) => void) => void; | ||
partner: Partner; | ||
itemsToGive: Item[]; | ||
itemsToReceive: Item[]; | ||
message: string; | ||
isOurOffer: boolean; | ||
} | ||
|
||
export interface Community {} |