diff --git a/src/ControlPanel.ts b/src/ControlPanel.ts
index eb72922..8ed02fe 100644
--- a/src/ControlPanel.ts
+++ b/src/ControlPanel.ts
@@ -1,4 +1,4 @@
-import { elClassId, getNumber, parseLocation, uniqId, waitForLoad } from './utils';
+import { parseLocation, uniqId, waitForLoad } from './utils';
 import { Scheduler } from './Scheduler';
 import { BuildingPageController } from './Page/BuildingPageController';
 import { UpgradeBuildingTask } from './Task/UpgradeBuildingTask';
@@ -18,6 +18,7 @@ import { Resources } from './Core/Resources';
 import { Village } from './Core/Village';
 import { calcGatheringTimings } from './Core/GatheringTimings';
 import { DataStorage } from './DataStorage';
+import { getBuildingPageAttributes, isBuildingPage } from './Page/PageDetectors';
 import { debounce } from 'debounce';
 
 interface QuickAction {
@@ -108,14 +109,8 @@ export class ControlPanel {
             showBuildingSlotIds(buildingsInQueue);
         }
 
-        if (p.pathname === '/build.php') {
-            const buildPage = new BuildingPageController(this.scheduler, {
-                buildId: getNumber(p.query.id),
-                buildTypeId: getNumber(elClassId(jQuery('#build').attr('class'), 'gid')),
-                categoryId: getNumber(p.query.category, 1),
-                sheetId: getNumber(p.query.s, 0),
-                tabId: getNumber(p.query.t, 0),
-            });
+        if (isBuildingPage()) {
+            const buildPage = new BuildingPageController(this.scheduler, getBuildingPageAttributes());
             buildPage.run();
         }
 
@@ -189,6 +184,7 @@ class VillageController {
     public readonly warehouse;
     public readonly granary;
     public readonly buildRemainingSeconds;
+    public readonly incomingResources: Resources;
 
     constructor(village: Village, state: VillageState, scheduler: Scheduler) {
         const resources = state.getResources();
@@ -225,6 +221,7 @@ class VillageController {
         this.warehouse = storage.warehouse;
         this.granary = storage.granary;
         this.buildRemainingSeconds = buildQueueInfo.seconds;
+        this.incomingResources = this.calcIncomingResources(state);
     }
 
     timeToRequired() {
@@ -243,4 +240,8 @@ class VillageController {
 
         return timings.hours * 3600;
     }
+
+    private calcIncomingResources(state: VillageState): Resources {
+        return state.getIncomingMerchants().reduce((m, i) => m.add(i.resources), new Resources(0, 0, 0, 0));
+    }
 }
diff --git a/src/Core/Buildings.ts b/src/Core/Buildings.ts
new file mode 100644
index 0000000..64e08b4
--- /dev/null
+++ b/src/Core/Buildings.ts
@@ -0,0 +1,6 @@
+export const WAREHOUSE_ID = 10;
+export const GARNER_ID = 11;
+export const MARKET_ID = 17;
+export const QUARTERS_ID = 19;
+export const HORSE_STABLE_ID = 20;
+export const EMBASSY_ID = 25;
diff --git a/src/Core/Market.ts b/src/Core/Market.ts
new file mode 100644
index 0000000..bf80868
--- /dev/null
+++ b/src/Core/Market.ts
@@ -0,0 +1,10 @@
+import { Resources } from './Resources';
+
+export class IncomingMerchant {
+    readonly resources: Resources;
+    readonly ts: number;
+    constructor(resources: Resources, ts: number) {
+        this.resources = resources;
+        this.ts = ts;
+    }
+}
diff --git a/src/DashboardView/VillageStateList.vue b/src/DashboardView/VillageStateList.vue
index 2f627fb..2811865 100644
--- a/src/DashboardView/VillageStateList.vue
+++ b/src/DashboardView/VillageStateList.vue
@@ -85,6 +85,23 @@
             
 | + | 
+            | Торговцы:+ | +              
++ | +              
++ | +              
++ | +              
++ | + | + | 
           
             |  | @@ -97,6 +114,7 @@
                 >->{{ v.name }}
               Казармы
+              Конюшни | 
         
@@ -109,6 +127,7 @@
 import { path } from '../utils';
 import ResourceBalance from './ResourceBalance';
 import VillageResource from './VillageResource';
+import { HORSE_STABLE_ID, MARKET_ID, QUARTERS_ID, WAREHOUSE_ID } from '../Core/Buildings';
 
 export default {
   components: {
@@ -126,13 +145,22 @@ export default {
       return path(name, args);
     },
     marketPath(fromVillage, toVillage) {
-      return path('/build.php', { newdid: fromVillage.id, gid: 17, t: 5, x: toVillage.crd.x, y: toVillage.crd.y });
+      return path('/build.php', {
+        newdid: fromVillage.id,
+        gid: MARKET_ID,
+        t: 5,
+        x: toVillage.crd.x,
+        y: toVillage.crd.y,
+      });
     },
     warehousePath(village) {
-      return path('/build.php', { newdid: village.id, gid: 10 });
+      return path('/build.php', { newdid: village.id, gid: WAREHOUSE_ID });
     },
     quartersPath(village) {
-      return path('/build.php', { newdid: village.id, gid: 19 });
+      return path('/build.php', { newdid: village.id, gid: QUARTERS_ID });
+    },
+    horseStablePath(village) {
+      return path('/build.php', { newdid: village.id, gid: HORSE_STABLE_ID });
     },
     secondsToTime(value) {
       if (value === 0) {
@@ -178,12 +206,9 @@ export default {
   border: 1px solid #ddd;
 }
 
-.performance-line td {
-  padding: 0 4px 4px;
-  font-size: 90%;
-}
-
-.required-line td {
+.performance-line td,
+.required-line td,
+.incoming-line td {
   padding: 0 4px 4px;
   font-size: 90%;
 }
diff --git a/src/DataStorage.ts b/src/DataStorage.ts
index 068346d..180e448 100644
--- a/src/DataStorage.ts
+++ b/src/DataStorage.ts
@@ -1,4 +1,5 @@
 import { ConsoleLogger, Logger, NullLogger } from './Logger';
+import { Resources } from './Core/Resources';
 
 const NAMESPACE = 'travian:v1';
 
@@ -8,6 +9,36 @@ function join(...parts: Array) {
     return parts.map(p => p.replace(/[:]+$/g, '').replace(/^[:]+/g, '')).join(':');
 }
 
+interface EmptyObjectFactory {
+    (): T;
+}
+
+interface ObjectMapper {
+    (item: any): T;
+}
+
+interface ObjectMapperOptions {
+    factory?: EmptyObjectFactory;
+    mapper?: ObjectMapper;
+}
+
+function createMapper(options: ObjectMapperOptions): ObjectMapper {
+    const { mapper, factory } = options;
+
+    if (mapper) {
+        return mapper;
+    }
+
+    if (factory) {
+        return plain => {
+            let item = factory();
+            return Object.assign(item, plain) as T;
+        };
+    }
+
+    throw new Error('Factory or mapper must be specified');
+}
+
 export class DataStorage {
     private readonly logger: Logger;
     private readonly name: string;
@@ -40,6 +71,21 @@ export class DataStorage {
         }
     }
 
+    getTyped(key: string, options: ObjectMapperOptions = {}): T {
+        let plain = this.get(key);
+        const mapper = createMapper(options);
+        return mapper(plain);
+    }
+
+    getTypedList(key: string, options: ObjectMapperOptions = {}): Array {
+        let plain = this.get(key);
+        if (!Array.isArray(plain)) {
+            return [];
+        }
+        const mapper = createMapper(options);
+        return (plain as Array).map(mapper);
+    }
+
     has(key: string): boolean {
         const fullKey = join(NAMESPACE, this.name, key);
         return storage.getItem(fullKey) !== null;
diff --git a/src/Grabber/GrabberManager.ts b/src/Grabber/GrabberManager.ts
index e51061a..dbaceb3 100644
--- a/src/Grabber/GrabberManager.ts
+++ b/src/Grabber/GrabberManager.ts
@@ -2,6 +2,7 @@ import { Grabber } from './Grabber';
 import { VillageResourceGrabber } from './VillageResourceGrabber';
 import { VillageOverviewPageGrabber } from './VillageOverviewPageGrabber';
 import { HeroPageGrabber } from './HeroPageGrabber';
+import { MarketPageGrabber } from './MarketPageGrabber';
 
 export class GrabberManager {
     private readonly grabbers: Array = [];
@@ -11,6 +12,7 @@ export class GrabberManager {
         this.grabbers.push(new VillageResourceGrabber());
         this.grabbers.push(new VillageOverviewPageGrabber());
         this.grabbers.push(new HeroPageGrabber());
+        this.grabbers.push(new MarketPageGrabber());
     }
 
     grab() {
diff --git a/src/Grabber/HeroPageGrabber.ts b/src/Grabber/HeroPageGrabber.ts
index fc056f9..b7f9f9d 100644
--- a/src/Grabber/HeroPageGrabber.ts
+++ b/src/Grabber/HeroPageGrabber.ts
@@ -1,21 +1,12 @@
 import { Grabber } from './Grabber';
-import {
-    grabActiveVillageId,
-    grabBuildingQueueInfo,
-    grabResourcesPerformance,
-    grabVillageList,
-} from '../Page/VillageBlock';
-import { VillageState } from '../State/VillageState';
-import { parseLocation } from '../utils';
-import { GrabError } from '../Errors';
-import { BuildingQueueInfo } from '../Game';
+import { grabVillageList } from '../Page/VillageBlock';
 import { HeroState } from '../State/HeroState';
 import { grabHeroAttributes, grabHeroVillage } from '../Page/HeroPage';
+import { isHeroPage } from '../Page/PageDetectors';
 
 export class HeroPageGrabber extends Grabber {
     grab(): void {
-        const p = parseLocation();
-        if (p.pathname !== '/hero.php') {
+        if (!isHeroPage()) {
             return;
         }
 
diff --git a/src/Grabber/MarketPageGrabber.ts b/src/Grabber/MarketPageGrabber.ts
new file mode 100644
index 0000000..4eeaa87
--- /dev/null
+++ b/src/Grabber/MarketPageGrabber.ts
@@ -0,0 +1,17 @@
+import { Grabber } from './Grabber';
+import { grabActiveVillageId } from '../Page/VillageBlock';
+import { VillageState } from '../State/VillageState';
+import { grabIncomingMerchants } from '../Page/BuildingPage';
+import { isMarketSendResourcesPage } from '../Page/PageDetectors';
+
+export class MarketPageGrabber extends Grabber {
+    grab(): void {
+        if (!isMarketSendResourcesPage()) {
+            return;
+        }
+
+        const villageId = grabActiveVillageId();
+        const state = new VillageState(villageId);
+        state.storeIncomingMerchants(grabIncomingMerchants());
+    }
+}
diff --git a/src/Page/BuildingPage.ts b/src/Page/BuildingPage.ts
index 62271f1..ccb106d 100644
--- a/src/Page/BuildingPage.ts
+++ b/src/Page/BuildingPage.ts
@@ -2,6 +2,7 @@ import { GrabError } from '../Errors';
 import { elClassId, getNumber, trimPrefix, uniqId } from '../utils';
 import { Resources } from '../Core/Resources';
 import { Coordinates } from '../Core/Village';
+import { IncomingMerchant } from '../Core/Market';
 
 export function clickBuildButton(typeId: number) {
     const section = jQuery(`#contract_building${typeId}`);
@@ -140,3 +141,18 @@ export function fillSendResourcesForm(resources: Resources, crd: Coordinates) {
 export function clickSendButton() {
     jQuery('#enabledButton').trigger('click');
 }
+
+export function grabIncomingMerchants(): ReadonlyArray {
+    const result: Array = [];
+    const root = jQuery('#merchantsOnTheWay .ownMerchants');
+    root.find('.traders').each((idx, el) => {
+        const $el = jQuery(el);
+        result.push(
+            new IncomingMerchant(
+                grabResourcesFromList($el.find('.resourceWrapper .resources')),
+                getNumber($el.find('.timer').attr('value'))
+            )
+        );
+    });
+    return result;
+}
diff --git a/src/Page/BuildingPageController.ts b/src/Page/BuildingPageController.ts
index 76cec3f..2e23288 100644
--- a/src/Page/BuildingPageController.ts
+++ b/src/Page/BuildingPageController.ts
@@ -9,24 +9,14 @@ import {
     createSendResourcesButton,
     createTrainTroopButtons,
     createUpgradeButton,
+    grabIncomingMerchants,
 } from './BuildingPage';
 import { BuildBuildingTask } from '../Task/BuildBuildingTask';
 import { Resources } from '../Core/Resources';
 import { Coordinates } from '../Core/Village';
 import { SendResourcesTask } from '../Task/SendResourcesTask';
-
-const MARKET_ID = 17;
-const QUARTERS_ID = 19;
-const HORSE_STABLE_ID = 20;
-const EMBASSY_ID = 25;
-
-export interface BuildingPageAttributes {
-    buildId: number;
-    buildTypeId: number;
-    categoryId: number;
-    sheetId: number;
-    tabId: number;
-}
+import { EMBASSY_ID, HORSE_STABLE_ID, QUARTERS_ID } from '../Core/Buildings';
+import { BuildingPageAttributes, isMarketSendResourcesPage } from './PageDetectors';
 
 export class BuildingPageController {
     private scheduler: Scheduler;
@@ -40,7 +30,7 @@ export class BuildingPageController {
     }
 
     run() {
-        const { buildTypeId, sheetId, tabId } = this.attributes;
+        const { buildTypeId, sheetId } = this.attributes;
         this.logger.log('BUILD PAGE DETECTED', 'ID', this.attributes.buildId, this.attributes);
 
         if (buildTypeId) {
@@ -61,7 +51,8 @@ export class BuildingPageController {
             createTrainTroopButtons((troopId, res, count) => this.onScheduleTrainTroopers(troopId, res, count));
         }
 
-        if (buildTypeId === MARKET_ID && tabId === 5) {
+        if (isMarketSendResourcesPage()) {
+            console.log('MERCH', grabIncomingMerchants());
             createSendResourcesButton((res, crd) => this.onSendResources(res, crd));
         }
     }
diff --git a/src/Page/PageDetectors.ts b/src/Page/PageDetectors.ts
new file mode 100644
index 0000000..cbb7120
--- /dev/null
+++ b/src/Page/PageDetectors.ts
@@ -0,0 +1,42 @@
+import { elClassId, getNumber, parseLocation } from '../utils';
+import { MARKET_ID } from '../Core/Buildings';
+
+export interface BuildingPageAttributes {
+    buildId: number;
+    buildTypeId: number;
+    categoryId: number;
+    sheetId: number;
+    tabId: number;
+}
+
+export function isBuildingPage() {
+    const p = parseLocation();
+    return p.pathname === '/build.php';
+}
+
+export function isHeroPage() {
+    const p = parseLocation();
+    return p.pathname === '/hero.php';
+}
+
+export function getBuildingPageAttributes(): BuildingPageAttributes {
+    if (!isBuildingPage()) {
+        throw Error('Not building page');
+    }
+    const p = parseLocation();
+    return {
+        buildId: getNumber(p.query.id),
+        buildTypeId: getNumber(elClassId(jQuery('#build').attr('class'), 'gid')),
+        categoryId: getNumber(p.query.category, 1),
+        sheetId: getNumber(p.query.s, 0),
+        tabId: getNumber(p.query.t, 0),
+    };
+}
+
+export function isMarketSendResourcesPage(): boolean {
+    if (!isBuildingPage()) {
+        return false;
+    }
+    const { buildTypeId, tabId } = getBuildingPageAttributes();
+    return buildTypeId === MARKET_ID && tabId === 5;
+}
diff --git a/src/State/VillageState.ts b/src/State/VillageState.ts
index 6338c59..04ae939 100644
--- a/src/State/VillageState.ts
+++ b/src/State/VillageState.ts
@@ -1,12 +1,18 @@
 import { DataStorage } from '../DataStorage';
 import { BuildingQueueInfo } from '../Game';
-import { Resources } from '../Core/Resources';
+import { Resources, ResourcesInterface } from '../Core/Resources';
 import { ResourceStorage } from '../Core/ResourceStorage';
+import { IncomingMerchant } from '../Core/Market';
 
 const RESOURCES_KEY = 'res';
 const CAPACITY_KEY = 'cap';
 const PERFORMANCE_KEY = 'perf';
 const BUILDING_QUEUE_KEY = 'bq';
+const INCOMING_MERCHANTS_KEY = 'im';
+
+const ResourceOptions = {
+    factory: () => new Resources(0, 0, 0, 0),
+};
 
 export class VillageState {
     private storage: DataStorage;
@@ -19,9 +25,7 @@ export class VillageState {
     }
 
     getResources(): Resources {
-        let plain = this.storage.get(RESOURCES_KEY);
-        let res = new Resources(0, 0, 0, 0);
-        return Object.assign(res, plain) as Resources;
+        return this.storage.getTyped(RESOURCES_KEY, ResourceOptions);
     }
 
     storeResourceStorage(storage: ResourceStorage) {
@@ -39,9 +43,7 @@ export class VillageState {
     }
 
     getResourcesPerformance(): Resources {
-        let plain = this.storage.get(PERFORMANCE_KEY);
-        let res = new Resources(0, 0, 0, 0);
-        return Object.assign(res, plain) as Resources;
+        return this.storage.getTyped(PERFORMANCE_KEY, ResourceOptions);
     }
 
     storeBuildingQueueInfo(info: BuildingQueueInfo): void {
@@ -53,4 +55,23 @@ export class VillageState {
         let res = new BuildingQueueInfo(0);
         return Object.assign(res, plain) as BuildingQueueInfo;
     }
+
+    storeIncomingMerchants(merchants: ReadonlyArray): void {
+        this.storage.set(
+            INCOMING_MERCHANTS_KEY,
+            merchants.map(m => ({ ...m.resources, ts: m.ts }))
+        );
+    }
+
+    getIncomingMerchants(): ReadonlyArray {
+        const objects = this.storage.getTypedList